15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/web_contents/web_drag_dest_gtk.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_view_host_impl.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/web_contents/drag_utils_gtk.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/web_contents/web_contents_impl.h"
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/web_contents_delegate.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_drag_dest_delegate.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/url_constants.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebInputEvent.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/clipboard/custom_data_helper.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/gtk_dnd_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_screen_util.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebDragOperation;
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebDragOperationNone;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kNumGtkHandlers = 5;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetModifierFlags(GtkWidget* widget) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int modifier_state = 0;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkModifierType state;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_window_get_pointer(gtk_widget_get_window(widget), NULL, NULL, &state);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state & GDK_SHIFT_MASK)
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    modifier_state |= blink::WebInputEvent::ShiftKey;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state & GDK_CONTROL_MASK)
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    modifier_state |= blink::WebInputEvent::ControlKey;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state & GDK_MOD1_MASK)
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    modifier_state |= blink::WebInputEvent::AltKey;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state & GDK_META_MASK)
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    modifier_state |= blink::WebInputEvent::MetaKey;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return modifier_state;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebDragDestGtk::WebDragDestGtk(WebContents* web_contents, GtkWidget* widget)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : web_contents_(web_contents),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget_(widget),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context_(NULL),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data_requests_(0),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(NULL),
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      canceled_(false),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method_factory_(this) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    NULL, 0,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               GDK_ACTION_LINK |
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               GDK_ACTION_MOVE));
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If adding a handler, make sure to update kNumGtkHandlers and add it to the
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |handlers_| array so that it can be disconnected later on.
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handlers_.reset(new int[kNumGtkHandlers]);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handlers_.get()[0] = g_signal_connect(
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      widget, "drag-motion", G_CALLBACK(OnDragMotionThunk), this);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handlers_.get()[1] = g_signal_connect(
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      widget, "drag-leave", G_CALLBACK(OnDragLeaveThunk), this);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handlers_.get()[2] = g_signal_connect(
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      widget, "drag-drop", G_CALLBACK(OnDragDropThunk), this);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handlers_.get()[3] = g_signal_connect(
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      widget, "drag-data-received", G_CALLBACK(OnDragDataReceivedThunk), this);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(tony): Need a drag-data-delete handler for moving content out of
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the WebContents.  http://crbug.com/38989
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handlers_.get()[4] = g_signal_connect(
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebDragDestGtk::~WebDragDestGtk() {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (widget_) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_drag_dest_unset(widget_);
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < kNumGtkHandlers; ++i)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      g_signal_handler_disconnect(widget_, handlers_.get()[i]);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (context_) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_drop_target_ = operation != WebDragOperationNone;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gdk_drag_status(context_, WebDragOpToGdkDragAction(operation),
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    drag_over_time_);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebDragDestGtk::DragLeave() {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRenderViewHost()->DragTargetDragLeave();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate())
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate()->OnDragLeave();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drop_data_.reset();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      GdkDragContext* context,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      gint x, gint y,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      guint time) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (context_ != context) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context_ = context;
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    drop_data_.reset(new DropData);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_drop_target_ = false;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate())
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate()->DragInitialize(web_contents_);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // text/plain must come before text/uri-list. This is a hack that works in
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // conjunction with OnDragDataReceived. Since some file managers populate
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // text/plain with file URLs when dragging files, we want to handle
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // text/uri-list after text/plain so that the plain text can be cleared if
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it's a file drag.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static int supported_targets[] = {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::TEXT_PLAIN,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::TEXT_URI_LIST,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::TEXT_HTML,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::NETSCAPE_URL,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::CHROME_NAMED_URL,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(estade): support image drags?
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::CUSTOM_DATA,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add the delegate's requested target if applicable. Need to do this here
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // since gtk_drag_get_data will dispatch to our drag-data-received.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data_requests_ = arraysize(supported_targets) + (delegate() ? 1 : 0);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_drag_get_data(widget_, context,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        ui::GetAtomForTarget(supported_targets[i]),
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        time);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate()) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_drag_get_data(widget_, context, delegate()->GetBookmarkTargetAtom(),
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        time);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (data_requests_ == 0) {
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (canceled_)
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return FALSE;
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetRenderViewHost()->DragTargetDragOver(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::ClientPoint(widget_),
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::ScreenPoint(widget_),
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GdkDragActionToWebDragOp(context->actions),
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetModifierFlags(widget_));
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate())
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate()->OnDragOver();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_over_time_ = time;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pretend we are a drag destination because we don't want to wait for
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the renderer to tell us if we really are or not.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebDragDestGtk::OnDragDataReceived(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkSelectionData* data, guint info, guint time) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We might get the data from an old get_data() request that we no longer
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // care about.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (context != context_)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_requests_--;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Decode the data.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gint data_length = gtk_selection_data_get_length(data);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const guchar* raw_data = gtk_selection_data_get_data(data);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkAtom target = gtk_selection_data_get_target(data);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (raw_data && data_length > 0) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the source can't provide us with valid data for a requested target,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // raw_data will be NULL.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (target == ui::GetAtomForTarget(ui::TEXT_PLAIN)) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      guchar* text = gtk_selection_data_get_text(data);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (text) {
1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        drop_data_->text = base::NullableString16(
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            UTF8ToUTF16(std::string(reinterpret_cast<const char*>(text))),
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            false);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        g_free(text);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (target == ui::GetAtomForTarget(ui::TEXT_URI_LIST)) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gchar** uris = gtk_selection_data_get_uris(data);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (uris) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        drop_data_->url = GURL();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Most file managers populate text/uri-list with file URLs when
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // dragging files. To avoid exposing file system paths to web content,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // file URLs are never set as the URL content for the drop.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // TODO(estade): Can the filenames have a non-UTF8 encoding?
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GURL url(*uri_iter);
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::FilePath file_path;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (url.SchemeIs(chrome::kFileScheme) &&
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              net::FileURLToFilePath(url, &file_path)) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            drop_data_->filenames.push_back(
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                DropData::FileInfo(UTF8ToUTF16(file_path.value()),
208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                   base::string16()));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // This is a hack. Some file managers also populate text/plain with
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // a file URL when dragging files, so we clear it to avoid exposing
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // it to the web content.
2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            drop_data_->text = base::NullableString16();
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else if (!drop_data_->url.is_valid()) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Also set the first non-file URL as the URL content for the drop.
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            drop_data_->url = url;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        g_strfreev(uris);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (target == ui::GetAtomForTarget(ui::TEXT_HTML)) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(estade): Can the html have a non-UTF8 encoding?
2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      drop_data_->html = base::NullableString16(
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UTF8ToUTF16(std::string(reinterpret_cast<const char*>(raw_data),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  data_length)),
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          false);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We leave the base URL empty.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (target == ui::GetAtomForTarget(ui::NETSCAPE_URL)) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string netscape_url(reinterpret_cast<const char*>(raw_data),
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               data_length);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t split = netscape_url.find_first_of('\n');
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (split != std::string::npos) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        drop_data_->url = GURL(netscape_url.substr(0, split));
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (split < netscape_url.size() - 1)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (target == ui::GetAtomForTarget(ui::CUSTOM_DATA)) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::ReadCustomDataIntoMap(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          raw_data, data_length, &drop_data_->custom_data);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (data_requests_ == 0) {
2457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Give the delegate an opportunity to cancel the drag.
2467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    canceled_ = !web_contents_->GetDelegate()->CanDragEnter(
2477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        web_contents_,
2487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        *drop_data_,
2497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        GdkDragActionToWebDragOp(context->actions));
2507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (canceled_) {
2517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      drag_over_time_ = time;
2527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      UpdateDragStatus(WebDragOperationNone);
2537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      drop_data_.reset();
2547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return;
2557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
2567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // doesn't have any data available for us. In this case we try to synthesize a
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // URL bookmark.
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that bookmark drag data is encoded in the same format for both
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GTK and Views, hence we can share the same logic here.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate() && target == delegate()->GetBookmarkTargetAtom()) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (raw_data && data_length > 0) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate()->OnReceiveDataFromGtk(data);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate()->OnReceiveProcessedData(drop_data_->url,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         drop_data_->url_title);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_requests_ == 0) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tell the renderer about the drag.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |x| and |y| are seemingly arbitrary at this point.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetRenderViewHost()->DragTargetDragEnter(
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *drop_data_.get(),
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::ClientPoint(widget_),
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::ScreenPoint(widget_),
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GdkDragActionToWebDragOp(context->actions),
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetModifierFlags(widget_));
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate())
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate()->OnDragEnter();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_over_time_ = time;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The drag has left our widget; forward this information to the renderer.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 guint time) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set |context_| to NULL to make sure we will recognize the next DragMotion
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as an enter.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  context_ = NULL;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (canceled_)
2977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
2987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sometimes we get a drag-leave event before getting a drag-data-received
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // event. In that case, we don't want to bother the renderer with a
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DragLeave event.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_requests_ != 0)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // preceded by a drag-leave. The renderer doesn't like getting the signals
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in this order so delay telling it about the drag-leave till we are sure
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we are not getting a drop as well.
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WebDragDestGtk::DragLeave, method_factory_.GetWeakPtr()));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called by GTK when the user releases the mouse, executing a drop.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    gint x, gint y, guint time) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel that drag leave!
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  method_factory_.InvalidateWeakPtrs();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetRenderViewHost()->
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DragTargetDrop(ui::ClientPoint(widget_), ui::ScreenPoint(widget_),
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetModifierFlags(widget_));
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate())
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate()->OnDrop();
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The second parameter is just an educated guess as to whether or not the
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // drag succeeded, but at least we will get the drag-end animation right
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sometimes.
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_finish(context, is_drop_target_, FALSE, time);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RenderViewHostImpl* WebDragDestGtk::GetRenderViewHost() const {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<RenderViewHostImpl*>(web_contents_->GetRenderViewHost());
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
340