- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / web_contents / web_drag_source_win.cc
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_RENDER_VIEW_HOST_CHANGED,
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_RENDER_VIEW_HOST_CHANGED) {
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