From 2497090b12ddedaf9b1f56ecfb711c5445638d30 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Mon, 23 Jan 2012 19:04:54 +0000 Subject: [PATCH] - Linux: Add support for HTML5 drag&drop (issue #40). - Linux: Fix GTK cefclient to properly shutdown on CTRL+c (issue #40). - Linux: Fix compile error due to v8_impl.cc revision 469 changes. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@475 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- cef.gyp | 4 + cef.gypi | 4 + libcef/browser_impl_gtk.cc | 5 +- libcef/browser_webview_delegate.cc | 8 + libcef/browser_webview_delegate.h | 12 +- libcef/browser_webview_delegate_gtk.cc | 35 +++- libcef/v8_impl.cc | 3 - libcef/web_drag_source_gtk.cc | 159 +++++++++++++++ libcef/web_drag_source_gtk.h | 47 +++++ libcef/web_drop_target_gtk.cc | 265 +++++++++++++++++++++++++ libcef/web_drop_target_gtk.h | 52 +++++ tests/cefclient/cefclient_gtk.cpp | 3 +- 12 files changed, 587 insertions(+), 10 deletions(-) create mode 100644 libcef/web_drag_source_gtk.cc create mode 100644 libcef/web_drag_source_gtk.h create mode 100644 libcef/web_drop_target_gtk.cc create mode 100644 libcef/web_drop_target_gtk.h diff --git a/cef.gyp b/cef.gyp index b00686fc7..a5ff86692 100644 --- a/cef.gyp +++ b/cef.gyp @@ -845,6 +845,10 @@ 'libcef/external_protocol_handler_gtk.cc', 'libcef/webview_host_gtk.cc', 'libcef/webwidget_host_gtk.cc', + 'libcef/web_drag_source_gtk.cc', + 'libcef/web_drag_source_gtk.h', + 'libcef/web_drop_target_gtk.cc', + 'libcef/web_drop_target_gtk.h', ], }], ], diff --git a/cef.gypi b/cef.gypi index 04ecebd5e..4b0931d98 100644 --- a/cef.gypi +++ b/cef.gypi @@ -19,6 +19,10 @@ # Don't use the chrome style plugin with CEF. 'clang_use_chrome_plugins': 0, }], + [ 'OS=="linux"', { + # Required for drag and drop helpers. + 'toolkit_views': 1, + }], ] }, } diff --git a/libcef/browser_impl_gtk.cc b/libcef/browser_impl_gtk.cc index c8dc867d1..28fa2cd0e 100644 --- a/libcef/browser_impl_gtk.cc +++ b/libcef/browser_impl_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Copyright (c) 2012 The Chromium Embedded Framework Authors. // Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -96,6 +96,9 @@ bool CefBrowserImpl::UIT_CreateBrowser(const CefString& url) { g_signal_connect(G_OBJECT(window_info_.m_Widget), "destroy", G_CALLBACK(window_destroyed), this); + if (!settings_.drag_drop_disabled) + delegate_->RegisterDragDrop(); + Unlock(); if (client_.get()) { diff --git a/libcef/browser_webview_delegate.cc b/libcef/browser_webview_delegate.cc index d762b2c68..1eb1704b1 100644 --- a/libcef/browser_webview_delegate.cc +++ b/libcef/browser_webview_delegate.cc @@ -8,6 +8,9 @@ // have initialized a MessageLoop before these methods are called. #include "libcef/browser_webview_delegate.h" + +#include + #include "libcef/browser_appcache_system.h" #include "libcef/browser_file_system.h" #include "libcef/browser_impl.h" @@ -77,6 +80,11 @@ #include "libcef/web_drop_target_win.h" #endif +#if defined(OS_LINUX) +#include "libcef/web_drag_source_gtk.h" +#include "libcef/web_drop_target_gtk.h" +#endif + using appcache::WebApplicationCacheHostImpl; using WebKit::WebApplicationCacheHost; using WebKit::WebApplicationCacheHostClient; diff --git a/libcef/browser_webview_delegate.h b/libcef/browser_webview_delegate.h index 3daf51bf2..11692e375 100644 --- a/libcef/browser_webview_delegate.h +++ b/libcef/browser_webview_delegate.h @@ -46,6 +46,11 @@ class BrowserDragDelegate; class WebDropTarget; #endif +#if defined(OS_LINUX) +class WebDragSource; +class WebDropTarget; +#endif + class CefBrowserImpl; class GURL; class WebWidgetHost; @@ -229,9 +234,11 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, void SetSelectTrailingWhitespaceEnabled(bool enabled); // Additional accessors -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) // Sets the webview as a drop target. void RegisterDragDrop(); +#endif +#if defined(OS_WIN) void RevokeDragDrop(); // Called after dragging has finished. @@ -343,6 +350,8 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, #if defined(OS_WIN) // Classes needed by drag and drop. scoped_refptr drag_delegate_; +#endif +#if defined(OS_WIN) || defined(OS_LINUX) scoped_refptr drop_target_; #endif @@ -351,6 +360,7 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, // Used for judging whether a new SetCursor call is actually changing the // cursor. GdkCursorType cursor_type_; + scoped_refptr drag_source_; #endif #if defined(OS_MACOSX) diff --git a/libcef/browser_webview_delegate_gtk.cc b/libcef/browser_webview_delegate_gtk.cc index b4a44cb66..5486c9d87 100644 --- a/libcef/browser_webview_delegate_gtk.cc +++ b/libcef/browser_webview_delegate_gtk.cc @@ -1,10 +1,13 @@ -// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Copyright (c) 2012 The Chromium Embedded Framework Authors. // Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "libcef/browser_webview_delegate.h" #include "libcef/browser_impl.h" +#include "libcef/drag_data_impl.h" +#include "libcef/web_drop_target_gtk.h" +#include "libcef/web_drag_source_gtk.h" #include "base/message_loop.h" #include "base/string_util.h" @@ -292,9 +295,28 @@ void BrowserWebViewDelegate::startDragging( WebDragOperationsMask mask, const WebImage& image, const WebPoint& image_offset) { - // TODO(port): Support drag and drop. - if (browser_->UIT_GetWebView()) + + if (browser_->settings().drag_drop_disabled) { browser_->UIT_GetWebView()->dragSourceSystemDragEnded(); + return; + } + + WebDropData drop_data(data); + + CefRefPtr client = browser_->GetClient(); + if (client.get()) { + CefRefPtr handler = client->GetDragHandler(); + if (handler.get()) { + CefRefPtr data(new CefDragDataImpl(drop_data)); + if (handler->OnDragStart(browser_, data, + static_cast(mask))) { + browser_->UIT_GetWebView()->dragSourceSystemDragEnded(); + return; + } + } + } + drag_source_ = new WebDragSource(browser_); + drag_source_->StartDragging(drop_data, mask, image, image_offset); } void BrowserWebViewDelegate::runModal() { @@ -355,6 +377,13 @@ void BrowserWebViewDelegate::HandleContextMenu(int selected_id) { } } +// Private methods ------------------------------------------------------------ + +void BrowserWebViewDelegate::RegisterDragDrop() { + DCHECK(!drop_target_); + drop_target_ = new WebDropTarget(browser_); +} + // Protected methods ---------------------------------------------------------- void BrowserWebViewDelegate::ShowJavaScriptAlert( diff --git a/libcef/v8_impl.cc b/libcef/v8_impl.cc index 361dd53f9..171523412 100644 --- a/libcef/v8_impl.cc +++ b/libcef/v8_impl.cc @@ -1021,9 +1021,6 @@ int CefV8ValueImpl::AdjustExternallyAllocatedMemory(int change_in_bytes) { if (counter == NULL) return 0; - v8::HandleScope handle_scope; - v8::Local obj = GetHandle()->ToObject(); - int new_value = *counter + change_in_bytes; if (new_value < 0) { NOTREACHED() << "External memory usage cannot be less than 0 bytes"; diff --git a/libcef/web_drag_source_gtk.cc b/libcef/web_drag_source_gtk.cc new file mode 100644 index 000000000..67388c8d1 --- /dev/null +++ b/libcef/web_drag_source_gtk.cc @@ -0,0 +1,159 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "libcef/web_drag_source_gtk.h" + +#include + +#include "libcef/browser_impl.h" +#include "libcef/cef_context.h" +#include "libcef/drag_data_impl.h" +#include "libcef/web_drop_target_gtk.h" + +#include "base/utf_string_conversions.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_util.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebDragData.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPoint.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebImage.h" +#include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/base/dragdrop/os_exchange_data_provider_gtk.h" +#include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/base/dragdrop/gtk_dnd_util.h" +#include "ui/gfx/gtk_util.h" +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/window_open_disposition.h" + + +using WebKit::WebDragOperation; +using WebKit::WebDragOperationNone; +using WebKit::WebDragOperationCopy; +using WebKit::WebDragOperationLink; +using WebKit::WebDragOperationMove; +using WebKit::WebDragOperationGeneric; +using WebKit::WebPoint; +using WebKit::WebView; +using WebKit::WebDragOperationsMask; +using ui::DragDropTypes; + +namespace { + +void drag_end(GtkWidget* widget, GdkDragContext* context, + WebDragSource* user_data) { + user_data->OnDragEnd(widget, context); +} + +bool drag_failed(GtkWidget* widget, GdkDragContext* context, + GtkDragResult result, WebDragSource* user_data) { + return user_data->OnDragFailed(widget, context, result); +} + +void drag_data_get(GtkWidget* widget, GdkDragContext* context, + GtkSelectionData* selection_data, guint target_type, + guint time, WebDragSource* user_data) { + user_data->OnDragDataGet(widget, context, selection_data, target_type, time); +} + +} // namespace + +WebDragSource::WebDragSource(CefBrowserImpl* browser) + : browser_(browser) { + widget_ = gtk_invisible_new(); + // At some point we might want to listen to drag-begin + g_signal_connect(widget_, "drag-end", G_CALLBACK(&drag_end), this); + g_signal_connect(widget_, "drag-failed", G_CALLBACK(&drag_failed), this); + g_signal_connect(widget_, "drag-data-get", G_CALLBACK(&drag_data_get), this); +} + +WebDragSource::~WebDragSource() { + gtk_widget_destroy(widget_); +} + +void WebDragSource::StartDragging(const WebDropData& drop_data, + WebDragOperationsMask mask, + const WebKit::WebImage& image, + const WebKit::WebPoint& image_offset) { + drop_data_.reset(new WebDropData(drop_data)); + int targets_mask = 0; + if (!drop_data.plain_text.empty()) + targets_mask |= ui::TEXT_PLAIN; + if (drop_data.url.is_valid()) { + targets_mask |= ui::TEXT_URI_LIST; + targets_mask |= ui::CHROME_NAMED_URL; + targets_mask |= ui::NETSCAPE_URL; + } + if (!drop_data.text_html.empty()) + targets_mask |= ui::TEXT_HTML; + GtkTargetList* tl = ui::GetTargetListFromCodeMask(targets_mask); + + GdkEvent* event = gtk_get_current_event(); + GdkDragContext* context = gtk_drag_begin(widget_, tl, + (GdkDragAction)DragDropTypes::DragOperationToGdkDragAction(mask), 1, + event); + if (!image.isNull()) { + const SkBitmap& bitmap = image.getSkBitmap(); + GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap); + gtk_drag_set_icon_pixbuf(context, pixbuf, image_offset.x, image_offset.y); + gdk_pixbuf_unref(pixbuf); + } else { + gtk_drag_set_icon_default(context); + } + gdk_event_free(event); +} + +void WebDragSource::OnDragEnd(GtkWidget* widget, GdkDragContext* context) { + gfx::Point client(0, 0); + gfx::Point screen(0, 0); + getView()->dragSourceEndedAt(client, screen, WebDragOperationNone); + getView()->dragSourceSystemDragEnded(); +} + +bool WebDragSource::OnDragFailed(GtkWidget* widget, GdkDragContext* context, + GtkDragResult result) { + gfx::Point client(0, 0); + gfx::Point screen(0, 0); + getView()->dragSourceEndedAt(client, screen, WebDragOperationNone); + return FALSE; +} + +void WebDragSource::OnDragDataGet(GtkWidget* sender, GdkDragContext* context, + GtkSelectionData* selection_data, + guint target_type, guint time) { + switch (target_type) { + case ui::TEXT_PLAIN: { + std::string utf8_text = UTF16ToUTF8(drop_data_->plain_text); + gtk_selection_data_set_text(selection_data, utf8_text.c_str(), + utf8_text.length()); + break; + } + + case ui::TEXT_HTML: { + std::string utf8_text = UTF16ToUTF8(drop_data_->text_html); + gtk_selection_data_set(selection_data, + ui::GetAtomForTarget(ui::TEXT_HTML), + 8, + reinterpret_cast(utf8_text.c_str()), + utf8_text.length()); + break; + } + + case ui::TEXT_URI_LIST: + case ui::CHROME_NAMED_URL: + case ui::NETSCAPE_URL: { + ui::WriteURLWithName(selection_data, drop_data_->url, + drop_data_->url_title, target_type); + break; + } + + default: + NOTREACHED(); + } +} + +WebKit::WebView* WebDragSource::getView() { + return browser_->UIT_GetWebView(); +} + diff --git a/libcef/web_drag_source_gtk.h b/libcef/web_drag_source_gtk.h new file mode 100644 index 000000000..076747b65 --- /dev/null +++ b/libcef/web_drag_source_gtk.h @@ -0,0 +1,47 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CEF_LIBCEF_WEB_DRAG_SOURCE_GTK_H_ +#define CEF_LIBCEF_WEB_DRAG_SOURCE_GTK_H_ + +#include +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h" + +class CefBrowserImpl; +class WebDropData; + +namespace WebKit { +class WebImage; +class WebPoint; +class WebView; +} + +class WebDragSource : public base::RefCounted { + public: + explicit WebDragSource(CefBrowserImpl* browser); + virtual ~WebDragSource(); + + void StartDragging(const WebDropData& drop_data, + WebKit::WebDragOperationsMask mask, + const WebKit::WebImage& image, + const WebKit::WebPoint& image_offset); + + void OnDragEnd(GtkWidget* widget, GdkDragContext* context); + bool OnDragFailed(GtkWidget* widget, GdkDragContext* context, + GtkDragResult result); + void OnDragDataGet(GtkWidget* sender, GdkDragContext* context, + GtkSelectionData* selection_data, guint target_type, + guint time); + + private: + WebKit::WebView* getView(); + scoped_ptr drop_data_; + CefBrowserImpl* browser_; + GtkWidget* widget_; +}; + +#endif // CEF_LIBCEF_WEB_DRAG_SOURCE_GTK_H_ diff --git a/libcef/web_drop_target_gtk.cc b/libcef/web_drop_target_gtk.cc new file mode 100644 index 000000000..e3c19b286 --- /dev/null +++ b/libcef/web_drop_target_gtk.cc @@ -0,0 +1,265 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "libcef/web_drop_target_gtk.h" + +#include + +#include "libcef/browser_impl.h" +#include "libcef/cef_context.h" +#include "libcef/drag_data_impl.h" + +#include "base/utf_string_conversions.h" +#include "base/bind.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_util.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebDragData.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPoint.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/base/dragdrop/os_exchange_data_provider_gtk.h" +#include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/base/dragdrop/gtk_dnd_util.h" +#include "ui/base/gtk/gtk_screen_utils.h" +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/window_open_disposition.h" + +using WebKit::WebDragOperation; +using WebKit::WebDragOperationNone; +using WebKit::WebDragOperationCopy; +using WebKit::WebDragOperationLink; +using WebKit::WebDragOperationMove; +using WebKit::WebDragOperationGeneric; +using WebKit::WebDragOperationsMask; +using WebKit::WebPoint; +using WebKit::WebView; +using ui::DragDropTypes; + +namespace { + +/// GTK callbacks +gboolean drag_motion(GtkWidget* widget, GdkDragContext* context, gint x, + gint y, guint time, WebDropTarget* user_data) { + return user_data->OnDragMove(widget, context, x, y, time); +} + +void drag_leave(GtkWidget* widget, GdkDragContext* context, guint time, + WebDropTarget* user_data) { + user_data->OnDragLeave(widget, context, time); +} + +gboolean drag_drop(GtkWidget* widget, GdkDragContext* context, gint x, + gint y, guint time, WebDropTarget* user_data) { + return user_data->OnDragDrop(widget, context, x, y, time); +} + +void drag_data_received(GtkWidget* widget, GdkDragContext* context, + gint x, gint y, GtkSelectionData* data, guint info, + guint time, WebDropTarget* user_data) { + user_data->OnDragDataReceived(widget, context, x, y, data, info, time); +} + +int supported_targets[] = { + ui::TEXT_PLAIN, + ui::TEXT_URI_LIST, + ui::TEXT_HTML, + ui::NETSCAPE_URL, + ui::CHROME_NAMED_URL, + ui::TEXT_PLAIN_NO_CHARSET, +}; + +WebDragOperationsMask _mask(GdkDragContext* context) { + GdkDragAction propsed_action = gdk_drag_context_get_suggested_action(context); + return (WebDragOperationsMask)DragDropTypes::GdkDragActionToDragOperation( + propsed_action); +} + +} // namespace + +WebDropTarget::WebDropTarget(CefBrowserImpl* browser) + : browser_(browser), + data_requests_(0), + context_(NULL), + method_factory_(this) { + GtkWidget* widget = browser->UIT_GetWebViewHost()->view_handle(); + gtk_drag_dest_set(widget, (GtkDestDefaults)0, NULL, 0, + static_cast(GDK_ACTION_COPY | GDK_ACTION_LINK | + GDK_ACTION_MOVE)); + g_signal_connect(widget, "drag-motion", G_CALLBACK(&drag_motion), this); + g_signal_connect(widget, "drag-leave", G_CALLBACK(&drag_leave), this); + g_signal_connect(widget, "drag-drop", G_CALLBACK(&drag_drop), this); + g_signal_connect(widget, "drag-data-received", + G_CALLBACK(&drag_data_received), this); +} + +WebDropTarget::~WebDropTarget() { +} + +WebKit::WebView* WebDropTarget::getView() { + return browser_->UIT_GetWebView(); +} + +BrowserWebViewDelegate* WebDropTarget::getDelegate() { + return browser_->UIT_GetWebViewDelegate(); +} + +bool WebDropTarget::OnDragMove(GtkWidget* widget, GdkDragContext* context, + gint x, gint y, guint time) { + WebView* webview = getView(); + gint widget_x, widget_y; + WebDragOperation operation; + gtk_widget_translate_coordinates(gtk_widget_get_toplevel(widget), widget, x, + y, &widget_x, &widget_y); + + // Request all the data and potentially start the DnD. + if (context_ != context) { + drop_data_.reset(new WebDropData); + data_requests_ = arraysize(supported_targets); + for (size_t i = 0; i < arraysize(supported_targets); ++i) { + gtk_drag_get_data(widget, context, + ui::GetAtomForTarget(supported_targets[i]), + time); + } + } else if (data_requests_ == 0) { + operation = webview->dragTargetDragOver(WebPoint(x, y), + WebPoint(widget_x, widget_y), + _mask(context)); + gdk_drag_status(context, + (GdkDragAction)DragDropTypes::DragOperationToGdkDragAction(operation), + time); + } + return TRUE; +} + +// Real DragLeave +void WebDropTarget::DragLeave() { + WebView* webview = getView(); + webview->dragTargetDragLeave(); +} + +// GTK Sends DragDrop (immediately) after DragLeave +// So post re-post DragLeave allowing us to behave like chromium expects. +void WebDropTarget::OnDragLeave(GtkWidget* widget, GdkDragContext* context, + guint time) { + context_ = NULL; + drop_data_.reset(); + MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(&WebDropTarget::DragLeave, method_factory_.GetWeakPtr())); +} + +bool WebDropTarget::OnDragDrop(GtkWidget* widget, GdkDragContext* context, + gint x, gint y, guint time) { + method_factory_.InvalidateWeakPtrs(); + + gint widget_x, widget_y; + gtk_widget_translate_coordinates(gtk_widget_get_toplevel(widget), widget, x, + y, &widget_x, &widget_y); + browser_->set_is_dropping(true); + + if (browser_->UIT_GetWebView()) { + browser_->UIT_GetWebView()->dragTargetDrop( + WebPoint(x, y), + WebPoint(widget_x, widget_y)); + } + browser_->set_is_dropping(false); + context_ = NULL; + gtk_drag_finish(context, TRUE, FALSE, time); + + return TRUE; +} + + +void WebDropTarget::OnDragDataReceived(GtkWidget* widget, + GdkDragContext* context, gint x, gint y, + GtkSelectionData* data, guint info, + guint time) { + WebDragOperation operation; + data_requests_--; + + // If the source can't provide us with valid data for a requested target, + // data->data will be NULL. + if (data->data && data->length > 0) { + if (data->target == ui::GetAtomForTarget(ui::TEXT_PLAIN) || + data->target == ui::GetAtomForTarget(ui::TEXT_PLAIN_NO_CHARSET)) { + guchar* text = gtk_selection_data_get_text(data); + if (text) { + drop_data_->plain_text = UTF8ToUTF16((const char*)text); + g_free(text); + } + } else if (data->target == ui::GetAtomForTarget(ui::TEXT_URI_LIST)) { + gchar** uris = gtk_selection_data_get_uris(data); + if (uris) { + drop_data_->url = GURL(); + for (gchar** uri_iter = uris; *uri_iter; uri_iter++) { + // Most file managers populate text/uri-list with file URLs when + // dragging files. To avoid exposing file system paths to web content, + // file URLs are never set as the URL content for the drop. + // TODO(estade): Can the filenames have a non-UTF8 encoding? + GURL url(*uri_iter); + FilePath file_path; + if (url.SchemeIs("file") && + net::FileURLToFilePath(url, &file_path)) { + drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value())); + // This is a hack. Some file managers also populate text/plain with + // a file URL when dragging files, so we clear it to avoid exposing + // it to the web content. + // drop_data_->plain_text.clear(); + } else if (!drop_data_->url.is_valid()) { + // Also set the first non-file URL as the URL content for the drop. + drop_data_->url = url; + } + } + g_strfreev(uris); + } + } else if (data->target == ui::GetAtomForTarget(ui::TEXT_HTML)) { + drop_data_->text_html = + UTF8ToUTF16(std::string(reinterpret_cast(data->data), + data->length)); + // We leave the base URL empty. + } else if (data->target == ui::GetAtomForTarget(ui::NETSCAPE_URL)) { + std::string netscape_url(reinterpret_cast(data->data), + data->length); + size_t split = netscape_url.find_first_of('\n'); + if (split != std::string::npos) { + drop_data_->url = GURL(netscape_url.substr(0, split)); + if (split < netscape_url.size() - 1) + drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1)); + } + } else if (data->target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) { + ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title); + } + } + + if (data_requests_ == 0) { + CefRefPtr client = browser_->GetClient(); + if (client.get()) { + CefRefPtr handler = client->GetDragHandler(); + if (handler.get()) { + CefRefPtr data(new CefDragDataImpl(*drop_data_.get())); + if (handler->OnDragEnter(browser_, data, + (cef_drag_operations_mask_t)_mask(context))) { + operation = WebDragOperationNone; + gdk_drag_status(context, + (GdkDragAction)DragDropTypes::DragOperationToGdkDragAction( + operation), + time); + return; + } + } + } + gint widget_x, widget_y; + gtk_widget_translate_coordinates(gtk_widget_get_toplevel(widget), widget, + x, y, &widget_x, &widget_y); + WebView* webview = getView(); + operation = webview->dragTargetDragEnter(drop_data_->ToDragData(), + WebPoint(x, y), + WebPoint(widget_x, widget_y), + _mask(context)); + gdk_drag_status(context, + (GdkDragAction)DragDropTypes::DragOperationToGdkDragAction(operation), + time); + context_ = context; + } +} diff --git a/libcef/web_drop_target_gtk.h b/libcef/web_drop_target_gtk.h new file mode 100644 index 000000000..0032551e0 --- /dev/null +++ b/libcef/web_drop_target_gtk.h @@ -0,0 +1,52 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CEF_LIBCEF_WEB_DROP_TARGET_GTK_H_ +#define CEF_LIBCEF_WEB_DROP_TARGET_GTK_H_ + +#include +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" + +class BrowserWebViewDelegate; +class CefBrowserImpl; +class WebDropData; + +namespace WebKit { +class WebView; +} + +class WebDropTarget : public base::RefCounted { + public: + explicit WebDropTarget(CefBrowserImpl* browser); + virtual ~WebDropTarget(); + + WebKit::WebView* getView(); + BrowserWebViewDelegate* getDelegate(); + + // Called by GTK callbacks + bool OnDragMove(GtkWidget* widget, GdkDragContext* context, gint x, gint y, + guint time); + void OnDragLeave(GtkWidget* widget, GdkDragContext* context, guint time); + bool OnDragDrop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, + guint time); + void OnDragEnd(GtkWidget* widget, GdkDragContext* context, guint time); + void OnDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint x, + gint y, GtkSelectionData* data, guint info, + guint time); + void DragLeave(); + + private: + CefBrowserImpl* browser_; + scoped_ptr drop_data_; + bool entered_; + int data_requests_; + GdkDragContext* context_; + base::WeakPtrFactory method_factory_; +}; + +#endif // CEF_LIBCEF_WEB_DROP_TARGET_GTK_H_ + diff --git a/tests/cefclient/cefclient_gtk.cpp b/tests/cefclient/cefclient_gtk.cpp index 2fed5879d..5b0afa081 100644 --- a/tests/cefclient/cefclient_gtk.cpp +++ b/tests/cefclient/cefclient_gtk.cpp @@ -27,8 +27,7 @@ void destroy(void) { } void TerminationSignalHandler(int signatl) { - CefShutdown(); - exit(0); + destroy(); } // Callback for Debug > Get Source... menu item.