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