| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 #include "chrome/browser/tab_contents/tab_contents_view_mac.h" | 5 #include "chrome/browser/tab_contents/tab_contents_view_mac.h" |
| 6 | 6 |
| 7 #include "base/sys_string_conversions.h" | 7 #include <string> |
| 8 |
| 8 #include "chrome/browser/browser.h" // TODO(beng): this dependency is awful. | 9 #include "chrome/browser/browser.h" // TODO(beng): this dependency is awful. |
| 9 #include "chrome/browser/cocoa/nsimage_cache.h" | |
| 10 #include "chrome/browser/cocoa/sad_tab_view.h" | 10 #include "chrome/browser/cocoa/sad_tab_view.h" |
| 11 #import "chrome/browser/cocoa/web_drag_source.h" |
| 11 #import "chrome/browser/cocoa/web_drop_target.h" | 12 #import "chrome/browser/cocoa/web_drop_target.h" |
| 12 #include "chrome/browser/renderer_host/render_widget_host.h" | 13 #include "chrome/browser/renderer_host/render_widget_host.h" |
| 13 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" | 14 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" |
| 14 #include "chrome/browser/tab_contents/render_view_context_menu_mac.h" | 15 #include "chrome/browser/tab_contents/render_view_context_menu_mac.h" |
| 15 #include "chrome/browser/tab_contents/tab_contents.h" | 16 #include "chrome/browser/tab_contents/tab_contents.h" |
| 16 #include "chrome/common/notification_type.h" | 17 #include "chrome/common/notification_type.h" |
| 17 #include "chrome/common/notification_service.h" | 18 #include "chrome/common/notification_service.h" |
| 18 #include "chrome/common/render_messages.h" | 19 #include "chrome/common/render_messages.h" |
| 19 #include "net/base/net_util.h" | |
| 20 #import "third_party/mozilla/include/NSPasteboard+Utils.h" | 20 #import "third_party/mozilla/include/NSPasteboard+Utils.h" |
| 21 | 21 |
| 22 #include "chrome/common/temp_scaffolding_stubs.h" | 22 #include "chrome/common/temp_scaffolding_stubs.h" |
| 23 | 23 |
| 24 @interface TabContentsViewCocoa (Private) | 24 @interface TabContentsViewCocoa (Private) |
| 25 - (id)initWithTabContentsViewMac:(TabContentsViewMac*)w; | 25 - (id)initWithTabContentsViewMac:(TabContentsViewMac*)w; |
| 26 - (void)processKeyboardEvent:(NSEvent*)event; | 26 - (void)processKeyboardEvent:(NSEvent*)event; |
| 27 - (TabContents*)tabContents; | |
| 28 - (void)registerDragTypes; | 27 - (void)registerDragTypes; |
| 29 - (void)setIsDropTarget:(BOOL)isTarget; | 28 - (void)setIsDropTarget:(BOOL)isTarget; |
| 29 - (void)startDragWithDropData:(const WebDropData&)dropData; |
| 30 @end | 30 @end |
| 31 | 31 |
| 32 // static | 32 // static |
| 33 TabContentsView* TabContentsView::Create(TabContents* tab_contents) { | 33 TabContentsView* TabContentsView::Create(TabContents* tab_contents) { |
| 34 return new TabContentsViewMac(tab_contents); | 34 return new TabContentsViewMac(tab_contents); |
| 35 } | 35 } |
| 36 | 36 |
| 37 TabContentsViewMac::TabContentsViewMac(TabContents* tab_contents) | 37 TabContentsViewMac::TabContentsViewMac(TabContents* tab_contents) |
| 38 : TabContentsView(tab_contents) { | 38 : TabContentsView(tab_contents) { |
| 39 registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED, | 39 registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED, |
| 40 Source<TabContents>(tab_contents)); | 40 Source<TabContents>(tab_contents)); |
| 41 } | 41 } |
| 42 | 42 |
| 43 TabContentsViewMac::~TabContentsViewMac() { | |
| 44 } | |
| 45 | |
| 46 void TabContentsViewMac::CreateView() { | 43 void TabContentsViewMac::CreateView() { |
| 47 TabContentsViewCocoa* view = | 44 TabContentsViewCocoa* view = |
| 48 [[TabContentsViewCocoa alloc] initWithTabContentsViewMac:this]; | 45 [[TabContentsViewCocoa alloc] initWithTabContentsViewMac:this]; |
| 49 cocoa_view_.reset(view); | 46 cocoa_view_.reset(view); |
| 50 } | 47 } |
| 51 | 48 |
| 52 RenderWidgetHostView* TabContentsViewMac::CreateViewForWidget( | 49 RenderWidgetHostView* TabContentsViewMac::CreateViewForWidget( |
| 53 RenderWidgetHost* render_widget_host) { | 50 RenderWidgetHost* render_widget_host) { |
| 54 DCHECK(!render_widget_host->view()); | 51 DCHECK(!render_widget_host->view()); |
| 55 RenderWidgetHostViewMac* view = | 52 RenderWidgetHostViewMac* view = |
| (...skipping 23 matching lines...) Expand all Loading... |
| 79 } | 76 } |
| 80 | 77 |
| 81 gfx::NativeWindow TabContentsViewMac::GetTopLevelNativeWindow() const { | 78 gfx::NativeWindow TabContentsViewMac::GetTopLevelNativeWindow() const { |
| 82 return [cocoa_view_.get() window]; | 79 return [cocoa_view_.get() window]; |
| 83 } | 80 } |
| 84 | 81 |
| 85 void TabContentsViewMac::GetContainerBounds(gfx::Rect* out) const { | 82 void TabContentsViewMac::GetContainerBounds(gfx::Rect* out) const { |
| 86 *out = [cocoa_view_.get() NSRectToRect:[cocoa_view_.get() bounds]]; | 83 *out = [cocoa_view_.get() NSRectToRect:[cocoa_view_.get() bounds]]; |
| 87 } | 84 } |
| 88 | 85 |
| 89 // Returns a drag pasteboard filled with the appropriate data. The types are | |
| 90 // populated in decending order of richness. | |
| 91 NSPasteboard* TabContentsViewMac::FillDragData( | |
| 92 const WebDropData& drop_data) { | |
| 93 NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; | |
| 94 [pasteboard declareTypes:[NSArray array] owner:nil]; | |
| 95 | |
| 96 // HTML. | |
| 97 if (!drop_data.text_html.empty()) { | |
| 98 [pasteboard addTypes:[NSArray arrayWithObject:NSHTMLPboardType] | |
| 99 owner:nil]; | |
| 100 [pasteboard setString:base::SysUTF16ToNSString(drop_data.text_html) | |
| 101 forType:NSHTMLPboardType]; | |
| 102 } | |
| 103 | |
| 104 // URL. | |
| 105 if (drop_data.url.is_valid()) { | |
| 106 // TODO(pinkerton/jrg): special javascript: handling for bookmark bar. Win | |
| 107 // doesn't allow you to drop js: bookmarks on the desktop (since they're | |
| 108 // meaningless) but does allow you to drop them on the bookmark bar (where | |
| 109 // they're intended to go generally). We need to figure out a private | |
| 110 // flavor for Bookmark dragging and then flag this down in the drag source. | |
| 111 [pasteboard addTypes:[NSArray arrayWithObject:NSURLPboardType] | |
| 112 owner:nil]; | |
| 113 NSString* url = base::SysUTF8ToNSString(drop_data.url.spec()); | |
| 114 NSString* title = base::SysUTF16ToNSString(drop_data.url_title); | |
| 115 [pasteboard setURLs:[NSArray arrayWithObject:url] | |
| 116 withTitles:[NSArray arrayWithObject:title]]; | |
| 117 } | |
| 118 | |
| 119 // Files. | |
| 120 // TODO(pinkerton): Hook up image drags, data is in drop_data.file_contents. | |
| 121 if (!drop_data.file_contents.empty()) { | |
| 122 #if 0 | |
| 123 // Images without ALT text will only have a file extension so we need to | |
| 124 // synthesize one from the provided extension and URL. | |
| 125 std::string filename_utf8 = | |
| 126 [base::SysUTF16ToNSString(drop_data.file_description_filename) | |
| 127 fileSystemRepresentation]; | |
| 128 FilePath file_name(filename_utf8); | |
| 129 file_name = file_name.BaseName().RemoveExtension(); | |
| 130 if (file_name.value().empty()) { | |
| 131 // Retrieve the name from the URL. | |
| 132 file_name = FilePath::FromWStringHack( | |
| 133 net::GetSuggestedFilename(drop_data.url, "", "", L"")); | |
| 134 } | |
| 135 std::string file_extension_utf8 = | |
| 136 [base::SysUTF16ToNSString(drop_data.file_extension) | |
| 137 fileSystemRepresentation]; | |
| 138 file_name = file_name.ReplaceExtension(file_extension_utf8); | |
| 139 NSArray* types = [NSArray arrayWithObjects:NSFileContentsPboardType, | |
| 140 NSFilenamesPboardType, | |
| 141 nil]; | |
| 142 [pasteboard addTypes:types owner:nil]; | |
| 143 NSArray* file_name_array = | |
| 144 [NSArray arrayWithObject:base::SysUTF8ToNSString(file_name.value())]; | |
| 145 [pasteboard setPropertyList:file_name_array forType:NSFilenamesPboardType]; | |
| 146 NSData* data = [NSData dataWithBytes:drop_data.file_contents.data() | |
| 147 length:drop_data.file_contents.length()]; | |
| 148 [pasteboard setData:data forType:NSFileContentsPboardType]; | |
| 149 #endif | |
| 150 } | |
| 151 | |
| 152 // Plain text. | |
| 153 if (!drop_data.plain_text.empty()) { | |
| 154 [pasteboard addTypes:[NSArray arrayWithObject:NSStringPboardType] | |
| 155 owner:nil]; | |
| 156 [pasteboard setString:base::SysUTF16ToNSString(drop_data.plain_text) | |
| 157 forType:NSStringPboardType]; | |
| 158 } | |
| 159 return pasteboard; | |
| 160 } | |
| 161 | |
| 162 void TabContentsViewMac::StartDragging(const WebDropData& drop_data) { | 86 void TabContentsViewMac::StartDragging(const WebDropData& drop_data) { |
| 163 // We are only allowed to call dragImage:... from inside mouseDragged:, which | 87 // We are only allowed to call dragImage:... from inside mouseDragged:, which |
| 164 // we will never be (we're called back async), but it seems that the mouse | 88 // we will never be (we're called back async), but it seems that the mouse |
| 165 // event is still always the proper left mouse drag, so everything works out | 89 // event is still always the proper left mouse drag, so everything works out |
| 166 // in the end. However, we occasionally get spurrious "start drag" messages | 90 // in the end. However, we occasionally get spurious "start drag" messages |
| 167 // from the back-end when we shouldn't. If we go through with the drag, Cocoa | 91 // from the back-end when we shouldn't. If we go through with the drag, Cocoa |
| 168 // asserts in a bad way. Just bail for now until we can figure out the root of | 92 // asserts in a bad way. Just bail for now until we can figure out the root of |
| 169 // why we're getting the messages. | 93 // why we're getting the messages. |
| 170 // TODO(pinkerton): http://crbug.com/16811 | 94 // TODO(pinkerton): http://crbug.com/16811 |
| 171 NSEvent* currentEvent = [NSApp currentEvent]; | 95 NSEvent* currentEvent = [NSApp currentEvent]; |
| 172 if ([currentEvent type] != NSLeftMouseDragged) { | 96 if ([currentEvent type] != NSLeftMouseDragged) { |
| 173 LOG(INFO) << "Spurious StartDragging() message"; | 97 LOG(INFO) << "Spurious StartDragging() message"; |
| 174 RenderViewHost* rvh = tab_contents()->render_view_host(); | 98 RenderViewHost* rvh = tab_contents()->render_view_host(); |
| 175 if (rvh) | 99 if (rvh) |
| 176 rvh->DragSourceSystemDragEnded(); | 100 rvh->DragSourceSystemDragEnded(); |
| 177 return; | 101 return; |
| 178 } | 102 } |
| 179 | 103 |
| 180 // Create an image to use for the drag. | 104 // The drag invokes a nested event loop, but we need to continue processing |
| 181 // TODO(pinkerton): Generate the proper image. This one will do in a pinch. | 105 // events. |
| 182 NSImage* dragImage = nsimage_cache::ImageNamed(@"nav.pdf"); | |
| 183 | |
| 184 NSPasteboard* pasteboard = FillDragData(drop_data); | |
| 185 | |
| 186 // Tell the view to start a drag using |cocoa_view_| as the drag source. The | |
| 187 // source will get notified when the drag completes (success or failure) so | |
| 188 // it can tell the render view host the drag is done. The drag invokes a | |
| 189 // nested event loop, but we need to continue processing events. | |
| 190 NSPoint mousePoint = [currentEvent locationInWindow]; | |
| 191 mousePoint = [cocoa_view_ convertPoint:mousePoint fromView:nil]; | |
| 192 MessageLoop::current()->SetNestableTasksAllowed(true); | 106 MessageLoop::current()->SetNestableTasksAllowed(true); |
| 193 [cocoa_view_ dragImage:dragImage | 107 [cocoa_view_ startDragWithDropData:drop_data]; |
| 194 at:mousePoint | |
| 195 offset:NSZeroSize | |
| 196 event:currentEvent | |
| 197 pasteboard:pasteboard | |
| 198 source:cocoa_view_ | |
| 199 slideBack:YES]; | |
| 200 MessageLoop::current()->SetNestableTasksAllowed(false); | 108 MessageLoop::current()->SetNestableTasksAllowed(false); |
| 201 } | 109 } |
| 202 | 110 |
| 203 void TabContentsViewMac::OnContentsDestroy() { | 111 void TabContentsViewMac::OnContentsDestroy() { |
| 204 } | 112 } |
| 205 | 113 |
| 206 void TabContentsViewMac::RenderViewCreated(RenderViewHost* host) { | 114 void TabContentsViewMac::RenderViewCreated(RenderViewHost* host) { |
| 207 // We want updates whenever the intrinsic width of the webpage | 115 // We want updates whenever the intrinsic width of the webpage |
| 208 // changes. Put the RenderView into that mode. | 116 // changes. Put the RenderView into that mode. |
| 209 int routing_id = host->routing_id(); | 117 int routing_id = host->routing_id(); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 } | 326 } |
| 419 | 327 |
| 420 - (void)copy:(id)sender { | 328 - (void)copy:(id)sender { |
| 421 [self tabContents]->Copy(); | 329 [self tabContents]->Copy(); |
| 422 } | 330 } |
| 423 | 331 |
| 424 - (void)paste:(id)sender { | 332 - (void)paste:(id)sender { |
| 425 [self tabContents]->Paste(); | 333 [self tabContents]->Paste(); |
| 426 } | 334 } |
| 427 | 335 |
| 336 - (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type { |
| 337 [dragSource_ lazyWriteToPasteboard:sender |
| 338 forType:type]; |
| 339 } |
| 340 |
| 341 - (void)startDragWithDropData:(const WebDropData&)dropData { |
| 342 dragSource_.reset([[WebDragSource alloc] |
| 343 initWithContentsView:self |
| 344 dropData:&dropData |
| 345 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]]); |
| 346 [dragSource_ startDrag]; |
| 347 } |
| 348 |
| 428 // NSDraggingSource methods | 349 // NSDraggingSource methods |
| 429 | 350 |
| 430 // Returns what kind of drag operations are available. This is a required | 351 // Returns what kind of drag operations are available. This is a required |
| 431 // method for NSDraggingSource. | 352 // method for NSDraggingSource. |
| 432 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { | 353 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { |
| 433 // TODO(pinkerton): I think this is right... | 354 // TODO(pinkerton): I think this is right... |
| 434 return NSDragOperationCopy; | 355 return NSDragOperationCopy; |
| 435 } | 356 } |
| 436 | 357 |
| 437 // Called when a drag initiated in our view ends. We need to make sure that | 358 // Called when a drag initiated in our view ends. |
| 438 // we tell WebCore so that it can go about processing things as normal. | |
| 439 - (void)draggedImage:(NSImage*)anImage | 359 - (void)draggedImage:(NSImage*)anImage |
| 440 endedAt:(NSPoint)screenPoint | 360 endedAt:(NSPoint)screenPoint |
| 441 operation:(NSDragOperation)operation { | 361 operation:(NSDragOperation)operation { |
| 442 RenderViewHost* rvh = [self tabContents]->render_view_host(); | 362 [dragSource_ endDragAt:screenPoint |
| 443 if (rvh) { | 363 isCancelled:(operation == NSDragOperationNone)]; |
| 444 rvh->DragSourceSystemDragEnded(); | |
| 445 | 364 |
| 446 // Convert |screenPoint| to view coordinates and flip it. | 365 // Might as well throw out this object now. |
| 447 NSPoint localPoint = [self convertPointFromBase:screenPoint]; | 366 dragSource_.reset(); |
| 448 NSRect viewFrame = [self frame]; | |
| 449 localPoint.y = viewFrame.size.height - localPoint.y; | |
| 450 // Flip |screenPoint|. | |
| 451 NSRect screenFrame = [[[self window] screen] frame]; | |
| 452 screenPoint.y = screenFrame.size.height - screenPoint.y; | |
| 453 | |
| 454 if (operation != NSDragOperationNone) | |
| 455 rvh->DragSourceEndedAt(localPoint.x, localPoint.y, | |
| 456 screenPoint.x, screenPoint.y); | |
| 457 else | |
| 458 rvh->DragSourceCancelledAt(localPoint.x, localPoint.y, | |
| 459 screenPoint.x, screenPoint.y); | |
| 460 } | |
| 461 } | 367 } |
| 462 | 368 |
| 463 // Called when a drag initiated in our view moves. We need to tell WebCore | 369 // Called when a drag initiated in our view moves. |
| 464 // so it can update anything watching for drag events. | |
| 465 - (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint { | 370 - (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint { |
| 466 RenderViewHost* rvh = [self tabContents]->render_view_host(); | 371 [dragSource_ moveDragTo:screenPoint]; |
| 467 if (rvh) { | 372 } |
| 468 // Convert |screenPoint| to view coordinates and flip it. | |
| 469 NSPoint localPoint = [self convertPointFromBase:screenPoint]; | |
| 470 NSRect viewFrame = [self frame]; | |
| 471 localPoint.y = viewFrame.size.height - localPoint.y; | |
| 472 // Flip |screenPoint|. | |
| 473 NSRect screenFrame = [[[self window] screen] frame]; | |
| 474 screenPoint.y = screenFrame.size.height - screenPoint.y; | |
| 475 | 373 |
| 476 rvh->DragSourceMovedTo(localPoint.x, localPoint.y, | 374 // Called when we're informed where a file should be dropped. |
| 477 screenPoint.x, screenPoint.y); | 375 - (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest { |
| 478 } | 376 if (![dropDest isFileURL]) |
| 377 return nil; |
| 378 |
| 379 NSString* file_name = [dragSource_ dragPromisedFileTo:[dropDest path]]; |
| 380 if (!file_name) |
| 381 return nil; |
| 382 |
| 383 return [NSArray arrayWithObject:file_name]; |
| 479 } | 384 } |
| 480 | 385 |
| 481 // NSDraggingDestination methods | 386 // NSDraggingDestination methods |
| 482 | 387 |
| 483 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { | 388 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { |
| 484 return [dropTarget_ draggingEntered:sender view:self]; | 389 return [dropTarget_ draggingEntered:sender view:self]; |
| 485 } | 390 } |
| 486 | 391 |
| 487 - (void)draggingExited:(id<NSDraggingInfo>)sender { | 392 - (void)draggingExited:(id<NSDraggingInfo>)sender { |
| 488 [dropTarget_ draggingExited:sender]; | 393 [dropTarget_ draggingExited:sender]; |
| 489 } | 394 } |
| 490 | 395 |
| 491 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { | 396 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { |
| 492 return [dropTarget_ draggingUpdated:sender view:self]; | 397 return [dropTarget_ draggingUpdated:sender view:self]; |
| 493 } | 398 } |
| 494 | 399 |
| 495 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { | 400 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { |
| 496 return [dropTarget_ performDragOperation:sender view:self]; | 401 return [dropTarget_ performDragOperation:sender view:self]; |
| 497 } | 402 } |
| 498 | 403 |
| 499 // Tons of stuff goes here, where we grab events going on in Cocoaland and send | 404 // Tons of stuff goes here, where we grab events going on in Cocoaland and send |
| 500 // them into the C++ system. TODO(avi): all that jazz | 405 // them into the C++ system. TODO(avi): all that jazz |
| 501 | 406 |
| 502 @end | 407 @end |
| OLD | NEW |