Home | History | Annotate | Download | only in web_contents
      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