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