1 // Copyright (c) 2011 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 #include "chrome/browser/tab_contents/web_drag_source_win.h" 6 7 #include "base/task.h" 8 #include "chrome/browser/tab_contents/web_drag_utils_win.h" 9 #include "content/browser/browser_thread.h" 10 #include "content/browser/renderer_host/render_view_host.h" 11 #include "content/browser/tab_contents/tab_contents.h" 12 #include "content/common/notification_source.h" 13 #include "content/common/notification_type.h" 14 15 using WebKit::WebDragOperationNone; 16 17 namespace { 18 19 static void GetCursorPositions(gfx::NativeWindow wnd, gfx::Point* client, 20 gfx::Point* screen) { 21 POINT cursor_pos; 22 GetCursorPos(&cursor_pos); 23 screen->SetPoint(cursor_pos.x, cursor_pos.y); 24 ScreenToClient(wnd, &cursor_pos); 25 client->SetPoint(cursor_pos.x, cursor_pos.y); 26 } 27 28 } // namespace 29 30 /////////////////////////////////////////////////////////////////////////////// 31 // WebDragSource, public: 32 33 WebDragSource::WebDragSource(gfx::NativeWindow source_wnd, 34 TabContents* tab_contents) 35 : ui::DragSource(), 36 source_wnd_(source_wnd), 37 render_view_host_(tab_contents->render_view_host()), 38 effect_(DROPEFFECT_NONE) { 39 registrar_.Add(this, NotificationType::TAB_CONTENTS_SWAPPED, 40 Source<TabContents>(tab_contents)); 41 registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED, 42 Source<TabContents>(tab_contents)); 43 } 44 45 WebDragSource::~WebDragSource() { 46 } 47 48 void WebDragSource::OnDragSourceCancel() { 49 // Delegate to the UI thread if we do drag-and-drop in the background thread. 50 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 51 BrowserThread::PostTask( 52 BrowserThread::UI, FROM_HERE, 53 NewRunnableMethod(this, &WebDragSource::OnDragSourceCancel)); 54 return; 55 } 56 57 if (!render_view_host_) 58 return; 59 60 gfx::Point client; 61 gfx::Point screen; 62 GetCursorPositions(source_wnd_, &client, &screen); 63 render_view_host_->DragSourceEndedAt(client.x(), client.y(), 64 screen.x(), screen.y(), 65 WebDragOperationNone); 66 } 67 68 void WebDragSource::OnDragSourceDrop() { 69 // On Windows, we check for drag end in IDropSource::QueryContinueDrag which 70 // happens before IDropTarget::Drop is called. HTML5 requires the "dragend" 71 // event to happen after the "drop" event. Since Windows calls these two 72 // directly after each other we can just post a task to handle the 73 // OnDragSourceDrop after the current task. 74 BrowserThread::PostTask( 75 BrowserThread::UI, FROM_HERE, 76 NewRunnableMethod(this, &WebDragSource::DelayedOnDragSourceDrop)); 77 } 78 79 void WebDragSource::DelayedOnDragSourceDrop() { 80 if (!render_view_host_) 81 return; 82 83 gfx::Point client; 84 gfx::Point screen; 85 GetCursorPositions(source_wnd_, &client, &screen); 86 render_view_host_->DragSourceEndedAt( 87 client.x(), client.y(), screen.x(), screen.y(), 88 web_drag_utils_win::WinDragOpToWebDragOp(effect_)); 89 } 90 91 void WebDragSource::OnDragSourceMove() { 92 // Delegate to the UI thread if we do drag-and-drop in the background thread. 93 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 94 BrowserThread::PostTask( 95 BrowserThread::UI, FROM_HERE, 96 NewRunnableMethod(this, &WebDragSource::OnDragSourceMove)); 97 return; 98 } 99 100 if (!render_view_host_) 101 return; 102 103 gfx::Point client; 104 gfx::Point screen; 105 GetCursorPositions(source_wnd_, &client, &screen); 106 render_view_host_->DragSourceMovedTo(client.x(), client.y(), 107 screen.x(), screen.y()); 108 } 109 110 void WebDragSource::Observe(NotificationType type, 111 const NotificationSource& source, const NotificationDetails& details) { 112 if (NotificationType::TAB_CONTENTS_SWAPPED == type) { 113 // When the tab contents get swapped, our render view host goes away. 114 // That's OK, we can continue the drag, we just can't send messages back to 115 // our drag source. 116 render_view_host_ = NULL; 117 } else if (NotificationType::TAB_CONTENTS_DISCONNECTED == type) { 118 // This could be possible when we close the tab and the source is still 119 // being used in DoDragDrop at the time that the virtual file is being 120 // downloaded. 121 render_view_host_ = NULL; 122 } 123 } 124