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