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
GetCursorPositions(gfx::NativeWindow wnd,gfx::Point * client,gfx::Point * screen)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
WebDragSource(gfx::NativeWindow source_wnd,TabContents * tab_contents)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
~WebDragSource()45 WebDragSource::~WebDragSource() {
46 }
47
OnDragSourceCancel()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
OnDragSourceDrop()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
DelayedOnDragSourceDrop()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
OnDragSourceMove()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
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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