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