summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-19 20:22:00 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-19 20:22:00 +0000
commit02bae0f37e6b09992f3b81792735010f28b9542e (patch)
treeb33485cba2d3f3049d7e801957759b268aa9257e /ui
parentcfe1d619ca7f651c509ce4a4b52540fd573fbcd3 (diff)
downloadchromium_src-02bae0f37e6b09992f3b81792735010f28b9542e.zip
chromium_src-02bae0f37e6b09992f3b81792735010f28b9542e.tar.gz
chromium_src-02bae0f37e6b09992f3b81792735010f28b9542e.tar.bz2
Move more dnd related files to ui/base
BUG=none TEST=none TBR=brettw Review URL: http://codereview.chromium.org/6250014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71828 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/base/dragdrop/download_file_interface.h51
-rw-r--r--ui/base/dragdrop/drag_drop_types.h35
-rw-r--r--ui/base/dragdrop/drag_drop_types_gtk.cc35
-rw-r--r--ui/base/dragdrop/drag_drop_types_win.cc34
-rw-r--r--ui/base/dragdrop/drag_source.cc55
-rw-r--r--ui/base/dragdrop/drag_source.h56
-rw-r--r--ui/base/dragdrop/drop_target.cc172
-rw-r--r--ui/base/dragdrop/drop_target.h134
-rw-r--r--ui/base/dragdrop/gtk_dnd_util.cc260
-rw-r--r--ui/base/dragdrop/gtk_dnd_util.h88
-rw-r--r--ui/base/dragdrop/gtk_dnd_util_unittest.cc81
-rw-r--r--ui/base/dragdrop/os_exchange_data.h2
-rw-r--r--ui/base/dragdrop/os_exchange_data_provider_gtk.cc6
13 files changed, 1005 insertions, 4 deletions
diff --git a/ui/base/dragdrop/download_file_interface.h b/ui/base/dragdrop/download_file_interface.h
new file mode 100644
index 0000000..1054370
--- /dev/null
+++ b/ui/base/dragdrop/download_file_interface.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef UI_BASE_DRAGDROP_DOWNLOAD_FILE_INTERFACE_H_
+#define UI_BASE_DRAGDROP_DOWNLOAD_FILE_INTERFACE_H_
+#pragma once
+
+#include "build/build_config.h"
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+
+#if defined(OS_WIN)
+#include <objidl.h>
+#endif
+
+class FilePath;
+
+namespace ui {
+
+// Defines the interface to observe the status of file download.
+class DownloadFileObserver
+ : public base::RefCountedThreadSafe<DownloadFileObserver> {
+ public:
+ virtual void OnDownloadCompleted(const FilePath& file_path) = 0;
+ virtual void OnDownloadAborted() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<DownloadFileObserver>;
+ virtual ~DownloadFileObserver() {}
+};
+
+// Defines the interface to control how a file is downloaded.
+class DownloadFileProvider
+ : public base::RefCountedThreadSafe<DownloadFileProvider> {
+ public:
+ virtual bool Start(DownloadFileObserver* observer) = 0;
+ virtual void Stop() = 0;
+#if defined(OS_WIN)
+ virtual IStream* GetStream() = 0;
+#endif
+
+ protected:
+ friend class base::RefCountedThreadSafe<DownloadFileProvider>;
+ virtual ~DownloadFileProvider() {}
+};
+
+} // namespace ui
+
+#endif // UI_BASE_DRAGDROP_DOWNLOAD_FILE_INTERFACE_H_
diff --git a/ui/base/dragdrop/drag_drop_types.h b/ui/base/dragdrop/drag_drop_types.h
new file mode 100644
index 0000000..7cdd614
--- /dev/null
+++ b/ui/base/dragdrop/drag_drop_types.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef UI_BASE_DRAGDROP_DRAG_DROP_TYPES_H_
+#define UI_BASE_DRAGDROP_DRAG_DROP_TYPES_H_
+#pragma once
+
+#include "build/build_config.h"
+
+#include "base/basictypes.h"
+
+namespace ui {
+
+class DragDropTypes {
+ public:
+ enum DragOperation {
+ DRAG_NONE = 0,
+ DRAG_MOVE = 1 << 0,
+ DRAG_COPY = 1 << 1,
+ DRAG_LINK = 1 << 2
+ };
+
+#if defined(OS_WIN)
+ static uint32 DragOperationToDropEffect(int drag_operation);
+ static int DropEffectToDragOperation(uint32 effect);
+#elif !defined(OS_MACOSX)
+ static int DragOperationToGdkDragAction(int drag_operation);
+ static int GdkDragActionToDragOperation(int gdk_drag_action);
+#endif
+};
+
+} // namespace ui
+
+#endif // UI_BASE_DRAGDROP_DRAG_DROP_TYPES_H_
diff --git a/ui/base/dragdrop/drag_drop_types_gtk.cc b/ui/base/dragdrop/drag_drop_types_gtk.cc
new file mode 100644
index 0000000..2a70d7e
--- /dev/null
+++ b/ui/base/dragdrop/drag_drop_types_gtk.cc
@@ -0,0 +1,35 @@
+// 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 "ui/base/dragdrop/drag_drop_types.h"
+
+#include <gtk/gtk.h>
+
+namespace ui {
+
+// static
+int ui::DragDropTypes::DragOperationToGdkDragAction(int drag_operation) {
+ int gdk_drag_action = 0;
+ if (drag_operation & DRAG_MOVE)
+ gdk_drag_action |= GDK_ACTION_MOVE;
+ if (drag_operation & DRAG_COPY)
+ gdk_drag_action |= GDK_ACTION_COPY;
+ if (drag_operation & DRAG_LINK)
+ gdk_drag_action |= GDK_ACTION_LINK;
+ return gdk_drag_action;
+}
+
+// static
+int ui::DragDropTypes::GdkDragActionToDragOperation(int gdk_drag_action) {
+ int drag_operation = DRAG_NONE;
+ if (gdk_drag_action & GDK_ACTION_COPY)
+ drag_operation |= DRAG_COPY;
+ if (gdk_drag_action & GDK_ACTION_MOVE)
+ drag_operation |= DRAG_MOVE;
+ if (gdk_drag_action & GDK_ACTION_LINK)
+ drag_operation |= DRAG_LINK;
+ return drag_operation;
+}
+
+} // namespace ui
diff --git a/ui/base/dragdrop/drag_drop_types_win.cc b/ui/base/dragdrop/drag_drop_types_win.cc
new file mode 100644
index 0000000..d6beff5
--- /dev/null
+++ b/ui/base/dragdrop/drag_drop_types_win.cc
@@ -0,0 +1,34 @@
+// 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 "ui/base/dragdrop/drag_drop_types.h"
+
+#include <oleidl.h>
+
+namespace ui {
+
+int ui::DragDropTypes::DropEffectToDragOperation(
+ uint32 effect) {
+ int drag_operation = DRAG_NONE;
+ if (effect & DROPEFFECT_LINK)
+ drag_operation |= DRAG_LINK;
+ if (effect & DROPEFFECT_COPY)
+ drag_operation |= DRAG_COPY;
+ if (effect & DROPEFFECT_MOVE)
+ drag_operation |= DRAG_MOVE;
+ return drag_operation;
+}
+
+uint32 ui::DragDropTypes::DragOperationToDropEffect(int drag_operation) {
+ uint32 drop_effect = DROPEFFECT_NONE;
+ if (drag_operation & DRAG_LINK)
+ drop_effect |= DROPEFFECT_LINK;
+ if (drag_operation & DRAG_COPY)
+ drop_effect |= DROPEFFECT_COPY;
+ if (drag_operation & DRAG_MOVE)
+ drop_effect |= DROPEFFECT_MOVE;
+ return drop_effect;
+}
+
+} // namespace ui
diff --git a/ui/base/dragdrop/drag_source.cc b/ui/base/dragdrop/drag_source.cc
new file mode 100644
index 0000000..0a777bd
--- /dev/null
+++ b/ui/base/dragdrop/drag_source.cc
@@ -0,0 +1,55 @@
+// 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 "ui/base/dragdrop/drag_source.h"
+
+namespace ui {
+
+DragSource::DragSource() : cancel_drag_(false) {
+}
+
+HRESULT DragSource::QueryContinueDrag(BOOL escape_pressed, DWORD key_state) {
+ if (cancel_drag_)
+ return DRAGDROP_S_CANCEL;
+
+ if (escape_pressed) {
+ OnDragSourceCancel();
+ return DRAGDROP_S_CANCEL;
+ }
+
+ if (!(key_state & MK_LBUTTON)) {
+ OnDragSourceDrop();
+ return DRAGDROP_S_DROP;
+ }
+
+ OnDragSourceMove();
+ return S_OK;
+}
+
+HRESULT DragSource::GiveFeedback(DWORD effect) {
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+HRESULT DragSource::QueryInterface(const IID& iid, void** object) {
+ *object = NULL;
+ if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IDropSource)) {
+ *object = this;
+ } else {
+ return E_NOINTERFACE;
+ }
+ AddRef();
+ return S_OK;
+}
+
+ULONG DragSource::AddRef() {
+ base::RefCountedThreadSafe<DragSource>::AddRef();
+ return 0;
+}
+
+ULONG DragSource::Release() {
+ base::RefCountedThreadSafe<DragSource>::Release();
+ return 0;
+}
+
+} // namespace ui
diff --git a/ui/base/dragdrop/drag_source.h b/ui/base/dragdrop/drag_source.h
new file mode 100644
index 0000000..1ae1656
--- /dev/null
+++ b/ui/base/dragdrop/drag_source.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef UI_BASE_DRAGDROP_DRAG_SOURCE_H_
+#define UI_BASE_DRAGDROP_DRAG_SOURCE_H_
+#pragma once
+
+#include <objidl.h>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+
+namespace ui {
+
+// A base IDropSource implementation. Handles notifications sent by an active
+// drag-drop operation as the user mouses over other drop targets on their
+// system. This object tells Windows whether or not the drag should continue,
+// and supplies the appropriate cursors.
+class DragSource : public IDropSource,
+ public base::RefCountedThreadSafe<DragSource> {
+ public:
+ DragSource();
+ virtual ~DragSource() {}
+
+ // Stop the drag operation at the next chance we get. This doesn't
+ // synchronously stop the drag (since Windows is controlling that),
+ // but lets us tell Windows to cancel the drag the next chance we get.
+ void CancelDrag() {
+ cancel_drag_ = true;
+ }
+
+ // IDropSource implementation:
+ HRESULT __stdcall QueryContinueDrag(BOOL escape_pressed, DWORD key_state);
+ HRESULT __stdcall GiveFeedback(DWORD effect);
+
+ // IUnknown implementation:
+ HRESULT __stdcall QueryInterface(const IID& iid, void** object);
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ protected:
+ virtual void OnDragSourceCancel() {}
+ virtual void OnDragSourceDrop() {}
+ virtual void OnDragSourceMove() {}
+
+ private:
+ // Set to true if we want to cancel the drag operation.
+ bool cancel_drag_;
+
+ DISALLOW_COPY_AND_ASSIGN(DragSource);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_DRAGDROP_DRAG_SOURCE_H_
diff --git a/ui/base/dragdrop/drop_target.cc b/ui/base/dragdrop/drop_target.cc
new file mode 100644
index 0000000..9cf1c9d
--- /dev/null
+++ b/ui/base/dragdrop/drop_target.cc
@@ -0,0 +1,172 @@
+// 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 "ui/base/dragdrop/drop_target.h"
+
+#include <shlobj.h>
+
+#include "base/logging.h"
+
+namespace ui {
+
+IDropTargetHelper* DropTarget::cached_drop_target_helper_ = NULL;
+int32 DropTarget::drag_identity_ = 0;
+
+DropTarget::DropTarget(HWND hwnd)
+ : hwnd_(hwnd),
+ suspended_(false),
+ ref_count_(0) {
+ DCHECK(hwnd);
+ HRESULT result = RegisterDragDrop(hwnd, this);
+ DCHECK(SUCCEEDED(result));
+}
+
+DropTarget::~DropTarget() {
+}
+
+// static
+IDropTargetHelper* DropTarget::DropHelper() {
+ if (!cached_drop_target_helper_) {
+ CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER,
+ IID_IDropTargetHelper,
+ reinterpret_cast<void**>(&cached_drop_target_helper_));
+ }
+ return cached_drop_target_helper_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DropTarget, IDropTarget implementation:
+
+HRESULT DropTarget::DragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect) {
+ // Tell the helper that we entered so it can update the drag image.
+ IDropTargetHelper* drop_helper = DropHelper();
+ if (drop_helper) {
+ drop_helper->DragEnter(GetHWND(), data_object,
+ reinterpret_cast<POINT*>(&cursor_position), *effect);
+ }
+
+ // You can't drag and drop within the same HWND.
+ if (suspended_) {
+ *effect = DROPEFFECT_NONE;
+ return S_OK;
+ }
+
+ // Update the drag identity, skipping 0.
+ if (++drag_identity_ == 0)
+ ++drag_identity_;
+
+ current_data_object_ = data_object;
+ POINT screen_pt = { cursor_position.x, cursor_position.y };
+ *effect = OnDragEnter(current_data_object_, key_state, screen_pt, *effect);
+ return S_OK;
+}
+
+HRESULT DropTarget::DragOver(DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect) {
+ // Tell the helper that we moved over it so it can update the drag image.
+ IDropTargetHelper* drop_helper = DropHelper();
+ if (drop_helper)
+ drop_helper->DragOver(reinterpret_cast<POINT*>(&cursor_position), *effect);
+
+ if (suspended_) {
+ *effect = DROPEFFECT_NONE;
+ return S_OK;
+ }
+
+ POINT screen_pt = { cursor_position.x, cursor_position.y };
+ *effect = OnDragOver(current_data_object_, key_state, screen_pt, *effect);
+ return S_OK;
+}
+
+HRESULT DropTarget::DragLeave() {
+ // Tell the helper that we moved out of it so it can update the drag image.
+ IDropTargetHelper* drop_helper = DropHelper();
+ if (drop_helper)
+ drop_helper->DragLeave();
+
+ if (suspended_)
+ return S_OK;
+
+ OnDragLeave(current_data_object_);
+
+ current_data_object_ = NULL;
+ return S_OK;
+}
+
+HRESULT DropTarget::Drop(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect) {
+ // Tell the helper that we dropped onto it so it can update the drag image.
+ IDropTargetHelper* drop_helper = DropHelper();
+ if (drop_helper) {
+ drop_helper->Drop(current_data_object_,
+ reinterpret_cast<POINT*>(&cursor_position), *effect);
+ }
+
+ if (suspended_) {
+ *effect = DROPEFFECT_NONE;
+ return S_OK;
+ }
+
+ POINT screen_pt = { cursor_position.x, cursor_position.y };
+ *effect = OnDrop(current_data_object_, key_state, screen_pt, *effect);
+ return S_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DropTarget, IUnknown implementation:
+
+HRESULT DropTarget::QueryInterface(const IID& iid, void** object) {
+ *object = NULL;
+ if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IDropTarget)) {
+ *object = this;
+ } else {
+ return E_NOINTERFACE;
+ }
+ AddRef();
+ return S_OK;
+}
+
+ULONG DropTarget::AddRef() {
+ return ++ref_count_;
+}
+
+ULONG DropTarget::Release() {
+ if (--ref_count_ == 0) {
+ delete this;
+ return 0U;
+ }
+ return ref_count_;
+}
+
+DWORD DropTarget::OnDragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect) {
+ return DROPEFFECT_NONE;
+}
+
+DWORD DropTarget::OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect) {
+ return DROPEFFECT_NONE;
+}
+
+void DropTarget::OnDragLeave(IDataObject* data_object) {
+}
+
+DWORD DropTarget::OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect) {
+ return DROPEFFECT_NONE;
+}
+
+} // namespace ui
diff --git a/ui/base/dragdrop/drop_target.h b/ui/base/dragdrop/drop_target.h
new file mode 100644
index 0000000..46b43c0
--- /dev/null
+++ b/ui/base/dragdrop/drop_target.h
@@ -0,0 +1,134 @@
+// 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.
+
+#ifndef UI_BASE_DRAGDROP_DROP_TARGET_H_
+#define UI_BASE_DRAGDROP_DROP_TARGET_H_
+#pragma once
+
+#include <objidl.h>
+
+#include "base/ref_counted.h"
+
+// Windows interface.
+struct IDropTargetHelper;
+
+namespace ui {
+
+// A DropTarget implementation that takes care of the nitty gritty
+// of dnd. While this class is concrete, subclasses will most likely
+// want to override various OnXXX methods.
+//
+// Because DropTarget is ref counted you shouldn't delete it directly,
+// rather wrap it in a scoped_refptr. Be sure and invoke RevokeDragDrop(m_hWnd)
+// before the HWND is deleted too.
+//
+// This class is meant to be used in a STA and is not multithread-safe.
+class DropTarget : public IDropTarget {
+ public:
+ // Create a new DropTarget associating it with the given HWND.
+ explicit DropTarget(HWND hwnd);
+ virtual ~DropTarget();
+
+ // When suspended is set to |true|, the drop target does not receive drops
+ // from drags initiated within the owning HWND.
+ bool suspended() const { return suspended_; }
+ void set_suspended(bool suspended) { suspended_ = suspended; }
+
+ // IDropTarget implementation:
+ HRESULT __stdcall DragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect);
+ HRESULT __stdcall DragOver(DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect);
+ HRESULT __stdcall DragLeave();
+ HRESULT __stdcall Drop(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect);
+
+ // IUnknown implementation:
+ HRESULT __stdcall QueryInterface(const IID& iid, void** object);
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ protected:
+ // Returns the hosting HWND.
+ HWND GetHWND() { return hwnd_; }
+
+ // Invoked when the cursor first moves over the hwnd during a dnd session.
+ // This should return a bitmask of the supported drop operations:
+ // DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_LINK and/or
+ // DROPEFFECT_MOVE.
+ virtual DWORD OnDragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect);
+
+ // Invoked when the cursor moves over the window during a dnd session.
+ // This should return a bitmask of the supported drop operations:
+ // DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_LINK and/or
+ // DROPEFFECT_MOVE.
+ virtual DWORD OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect);
+
+ // Invoked when the cursor moves outside the bounds of the hwnd during a
+ // dnd session.
+ virtual void OnDragLeave(IDataObject* data_object);
+
+ // Invoked when the drop ends on the window. This should return the operation
+ // that was taken.
+ virtual DWORD OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect);
+
+ // Return the drag identity.
+ static int32 GetDragIdentity() { return drag_identity_; }
+
+ private:
+ // Returns the cached drop helper, creating one if necessary. The returned
+ // object is not addrefed. May return NULL if the object couldn't be created.
+ static IDropTargetHelper* DropHelper();
+
+ // The data object currently being dragged over this drop target.
+ scoped_refptr<IDataObject> current_data_object_;
+
+ // A helper object that is used to provide drag image support while the mouse
+ // is dragging over the content area.
+ //
+ // DO NOT ACCESS DIRECTLY! Use DropHelper() instead, which will lazily create
+ // this if it doesn't exist yet. This object can take tens of milliseconds to
+ // create, and we don't want to block any window opening for this, especially
+ // since often, DnD will never be used. Instead, we force this penalty to the
+ // first time it is actually used.
+ static IDropTargetHelper* cached_drop_target_helper_;
+
+ // The drag identity (id). An up-counter that increases when the cursor first
+ // moves over the HWND in a DnD session (OnDragEnter). 0 is reserved to mean
+ // the "no/unknown" identity, and is used for initialization. The identity is
+ // sent to the renderer in drag enter notifications. Note: the identity value
+ // is passed over the renderer NPAPI interface to gears, so use int32 instead
+ // of int here.
+ static int32 drag_identity_;
+
+ // The HWND of the source. This HWND is used to determine coordinates for
+ // mouse events that are sent to the renderer notifying various drag states.
+ HWND hwnd_;
+
+ // Whether or not we are currently processing drag notifications for drags
+ // initiated in this window.
+ bool suspended_;
+
+ LONG ref_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(DropTarget);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_DRAGDROP_DROP_TARGET_H_
diff --git a/ui/base/dragdrop/gtk_dnd_util.cc b/ui/base/dragdrop/gtk_dnd_util.cc
new file mode 100644
index 0000000..d9fea82
--- /dev/null
+++ b/ui/base/dragdrop/gtk_dnd_util.cc
@@ -0,0 +1,260 @@
+// 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 "ui/base/dragdrop/gtk_dnd_util.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/utf_string_conversions.h"
+#include "googleurl/src/gurl.h"
+
+static const int kBitsPerByte = 8;
+
+namespace ui {
+
+namespace {
+
+void AddTargetToList(GtkTargetList* targets, int target_code) {
+ switch (target_code) {
+ case ui::TEXT_PLAIN:
+ gtk_target_list_add_text_targets(targets, ui::TEXT_PLAIN);
+ break;
+
+ case ui::TEXT_URI_LIST:
+ gtk_target_list_add_uri_targets(targets, ui::TEXT_URI_LIST);
+ break;
+
+ case ui::TEXT_HTML:
+ gtk_target_list_add(
+ targets, ui::GetAtomForTarget(ui::TEXT_HTML), 0, ui::TEXT_HTML);
+ break;
+
+ case ui::NETSCAPE_URL:
+ gtk_target_list_add(targets,
+ ui::GetAtomForTarget(ui::NETSCAPE_URL), 0, ui::NETSCAPE_URL);
+ break;
+
+ case ui::CHROME_TAB:
+ case ui::CHROME_BOOKMARK_ITEM:
+ case ui::CHROME_NAMED_URL:
+ gtk_target_list_add(targets, ui::GetAtomForTarget(target_code),
+ GTK_TARGET_SAME_APP, target_code);
+ break;
+
+ case ui::DIRECT_SAVE_FILE:
+ gtk_target_list_add(targets,
+ ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE), 0, ui::DIRECT_SAVE_FILE);
+ break;
+
+ default:
+ NOTREACHED() << " Unexpected target code: " << target_code;
+ }
+}
+
+} // namespace
+
+GdkAtom GetAtomForTarget(int target) {
+ switch (target) {
+ case CHROME_TAB:
+ static GdkAtom tab_atom = gdk_atom_intern(
+ const_cast<char*>("application/x-chrome-tab"), false);
+ return tab_atom;
+
+ case TEXT_HTML:
+ static GdkAtom html_atom = gdk_atom_intern(
+ const_cast<char*>("text/html"), false);
+ return html_atom;
+
+ case CHROME_BOOKMARK_ITEM:
+ static GdkAtom bookmark_atom = gdk_atom_intern(
+ const_cast<char*>("application/x-chrome-bookmark-item"), false);
+ return bookmark_atom;
+
+ case TEXT_PLAIN:
+ static GdkAtom text_atom = gdk_atom_intern(
+ const_cast<char*>("text/plain;charset=utf-8"), false);
+ return text_atom;
+
+ case TEXT_URI_LIST:
+ static GdkAtom uris_atom = gdk_atom_intern(
+ const_cast<char*>("text/uri-list"), false);
+ return uris_atom;
+
+ case CHROME_NAMED_URL:
+ static GdkAtom named_url = gdk_atom_intern(
+ const_cast<char*>("application/x-chrome-named-url"), false);
+ return named_url;
+
+ case NETSCAPE_URL:
+ static GdkAtom netscape_url = gdk_atom_intern(
+ const_cast<char*>("_NETSCAPE_URL"), false);
+ return netscape_url;
+
+ case TEXT_PLAIN_NO_CHARSET:
+ static GdkAtom text_no_charset_atom = gdk_atom_intern(
+ const_cast<char*>("text/plain"), false);
+ return text_no_charset_atom;
+
+ case DIRECT_SAVE_FILE:
+ static GdkAtom xds_atom = gdk_atom_intern(
+ const_cast<char*>("XdndDirectSave0"), false);
+ return xds_atom;
+
+ default:
+ NOTREACHED();
+ }
+
+ return NULL;
+}
+
+GtkTargetList* GetTargetListFromCodeMask(int code_mask) {
+ GtkTargetList* targets = gtk_target_list_new(NULL, 0);
+
+ for (size_t i = 1; i < INVALID_TARGET; i = i << 1) {
+ if (i == CHROME_WEBDROP_FILE_CONTENTS)
+ continue;
+
+ if (i & code_mask)
+ AddTargetToList(targets, i);
+ }
+
+ return targets;
+}
+
+void SetSourceTargetListFromCodeMask(GtkWidget* source, int code_mask) {
+ GtkTargetList* targets = GetTargetListFromCodeMask(code_mask);
+ gtk_drag_source_set_target_list(source, targets);
+ gtk_target_list_unref(targets);
+}
+
+void SetDestTargetList(GtkWidget* dest, const int* target_codes) {
+ GtkTargetList* targets = gtk_target_list_new(NULL, 0);
+
+ for (size_t i = 0; target_codes[i] != -1; ++i) {
+ AddTargetToList(targets, target_codes[i]);
+ }
+
+ gtk_drag_dest_set_target_list(dest, targets);
+ gtk_target_list_unref(targets);
+}
+
+void WriteURLWithName(GtkSelectionData* selection_data,
+ const GURL& url,
+ string16 title,
+ int type) {
+ if (title.empty()) {
+ // We prefer to not have empty titles. Set it to the filename extracted
+ // from the URL.
+ title = UTF8ToUTF16(url.ExtractFileName());
+ }
+
+ switch (type) {
+ case TEXT_PLAIN: {
+ gtk_selection_data_set_text(selection_data, url.spec().c_str(),
+ url.spec().length());
+ break;
+ }
+ case TEXT_URI_LIST: {
+ gchar* uri_array[2];
+ uri_array[0] = strdup(url.spec().c_str());
+ uri_array[1] = NULL;
+ gtk_selection_data_set_uris(selection_data, uri_array);
+ free(uri_array[0]);
+ break;
+ }
+ case CHROME_NAMED_URL: {
+ Pickle pickle;
+ pickle.WriteString(UTF16ToUTF8(title));
+ pickle.WriteString(url.spec());
+ gtk_selection_data_set(
+ selection_data,
+ GetAtomForTarget(ui::CHROME_NAMED_URL),
+ kBitsPerByte,
+ reinterpret_cast<const guchar*>(pickle.data()),
+ pickle.size());
+ break;
+ }
+ case NETSCAPE_URL: {
+ // _NETSCAPE_URL format is URL + \n + title.
+ std::string utf8_text = url.spec() + "\n" + UTF16ToUTF8(title);
+ gtk_selection_data_set(selection_data,
+ selection_data->target,
+ kBitsPerByte,
+ reinterpret_cast<const guchar*>(utf8_text.c_str()),
+ utf8_text.length());
+ break;
+ }
+
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+bool ExtractNamedURL(GtkSelectionData* selection_data,
+ GURL* url,
+ string16* title) {
+ if (!selection_data || selection_data->length <= 0)
+ return false;
+
+ Pickle data(reinterpret_cast<char*>(selection_data->data),
+ selection_data->length);
+ void* iter = NULL;
+ std::string title_utf8, url_utf8;
+ if (!data.ReadString(&iter, &title_utf8) ||
+ !data.ReadString(&iter, &url_utf8)) {
+ return false;
+ }
+
+ GURL gurl(url_utf8);
+ if (!gurl.is_valid())
+ return false;
+
+ *url = gurl;
+ *title = UTF8ToUTF16(title_utf8);
+ return true;
+}
+
+bool ExtractURIList(GtkSelectionData* selection_data, std::vector<GURL>* urls) {
+ gchar** uris = gtk_selection_data_get_uris(selection_data);
+ if (!uris)
+ return false;
+
+ for (size_t i = 0; uris[i] != NULL; ++i) {
+ GURL url(uris[i]);
+ if (url.is_valid())
+ urls->push_back(url);
+ }
+
+ g_strfreev(uris);
+ return true;
+}
+
+bool ExtractNetscapeURL(GtkSelectionData* selection_data,
+ GURL* url,
+ string16* title) {
+ if (!selection_data || selection_data->length <= 0)
+ return false;
+
+ // Find the first '\n' in the data. It is the separator between the url and
+ // the title.
+ std::string data(reinterpret_cast<char*>(selection_data->data),
+ selection_data->length);
+ std::string::size_type newline = data.find('\n');
+ if (newline == std::string::npos)
+ return false;
+
+ GURL gurl(data.substr(0, newline));
+ if (!gurl.is_valid())
+ return false;
+
+ *url = gurl;
+ *title = UTF8ToUTF16(data.substr(newline + 1));
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/base/dragdrop/gtk_dnd_util.h b/ui/base/dragdrop/gtk_dnd_util.h
new file mode 100644
index 0000000..5a0adde
--- /dev/null
+++ b/ui/base/dragdrop/gtk_dnd_util.h
@@ -0,0 +1,88 @@
+// 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.
+
+#ifndef UI_BASE_DRAGDROP_GTK_DND_UTIL_H_
+#define UI_BASE_DRAGDROP_GTK_DND_UTIL_H_
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include <vector>
+
+#include "base/string16.h"
+
+class GURL;
+
+namespace ui {
+
+// Registry of all internal int codes for drag and drop.
+enum {
+ // Intra-application types.
+ CHROME_TAB = 1 << 0,
+ CHROME_BOOKMARK_ITEM = 1 << 1,
+ CHROME_WEBDROP_FILE_CONTENTS = 1 << 2,
+ CHROME_NAMED_URL = 1 << 3,
+
+ // Standard types.
+ TEXT_PLAIN = 1 << 4,
+ TEXT_URI_LIST = 1 << 5,
+ TEXT_HTML = 1 << 6,
+
+ // Other types. NETSCAPE_URL is provided for compatibility with other
+ // apps.
+ NETSCAPE_URL = 1 << 7,
+
+ // Used for drag-out download.
+ TEXT_PLAIN_NO_CHARSET = 1 << 8,
+ DIRECT_SAVE_FILE = 1 << 9,
+
+ INVALID_TARGET = 1 << 10,
+};
+
+// Get the atom for a given target (of the above enum type). Will return NULL
+// for non-custom targets, such as CHROME_TEXT_PLAIN.
+GdkAtom GetAtomForTarget(int target);
+
+// Creates a target list from the given mask. The mask should be an OR of
+// CHROME_* values. The target list is returned with ref count 1; the caller
+// is responsible for calling gtk_target_list_unref() when it is no longer
+// needed.
+// Since the MIME type for WEBDROP_FILE_CONTENTS depends on the file's
+// contents, that flag is ignored by this function. It is the responsibility
+// of the client code to do the right thing.
+GtkTargetList* GetTargetListFromCodeMask(int code_mask);
+
+// Set the drag target list for |source| with the target list that
+// corresponds to |code_mask|.
+void SetSourceTargetListFromCodeMask(GtkWidget* source, int code_mask);
+
+// Set the accepted targets list for |dest|. The |target_codes| array should
+// be sorted in preference order and should be terminated with -1.
+void SetDestTargetList(GtkWidget* dest, const int* target_codes);
+
+// Write a URL to the selection in the given type.
+void WriteURLWithName(GtkSelectionData* selection_data,
+ const GURL& url,
+ string16 title,
+ int type);
+
+// Extracts data of type CHROME_NAMED_URL from |selection_data| into
+// |url| and |title|. Returns true if the url/title were safely extracted
+// and the url is valid.
+bool ExtractNamedURL(GtkSelectionData* selection_data,
+ GURL* url,
+ string16* title);
+
+// Extracts data of type TEXT_URI_LIST from |selection_data| into |urls|.
+bool ExtractURIList(GtkSelectionData* selection_data,
+ std::vector<GURL>* urls);
+
+// Extracts a Netscape URL (url\ntitle) from |selection_data|.
+bool ExtractNetscapeURL(GtkSelectionData* selection_data,
+ GURL* url,
+ string16* title);
+
+} // namespace ui
+
+#endif // UI_BASE_DRAGDROP_GTK_DND_UTIL_H_
diff --git a/ui/base/dragdrop/gtk_dnd_util_unittest.cc b/ui/base/dragdrop/gtk_dnd_util_unittest.cc
new file mode 100644
index 0000000..33e5a6b
--- /dev/null
+++ b/ui/base/dragdrop/gtk_dnd_util_unittest.cc
@@ -0,0 +1,81 @@
+// 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 <string>
+
+#include "base/pickle.h"
+#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/dragdrop/gtk_dnd_util.h"
+
+namespace ui {
+
+TEST(GtkDndUtilTest, ExtractNamedURLValid) {
+ const std::string kTitle = "title";
+ const std::string kUrl = "http://www.foobar.com/";
+ Pickle pickle;
+ pickle.WriteString(kTitle);
+ pickle.WriteString(kUrl);
+
+ GtkSelectionData data;
+ scoped_array<guchar> test_data(new guchar[pickle.size()]);
+ memcpy(test_data.get(), pickle.data(), pickle.size());
+ data.data = test_data.get();
+ data.length = pickle.size();
+
+ GURL url;
+ string16 title;
+ ASSERT_EQ(true, ui::ExtractNamedURL(&data, &url, &title));
+ EXPECT_EQ(UTF8ToUTF16(kTitle), title);
+ EXPECT_EQ(GURL(kUrl), url);
+}
+
+TEST(GtkDndUtilTest, ExtractNamedURLInvalidURL) {
+ const std::string kTitle = "title";
+ const std::string kBadUrl = "foobar";
+ Pickle pickle;
+ pickle.WriteString(kTitle);
+ pickle.WriteString(kBadUrl);
+
+ GtkSelectionData data;
+ scoped_array<guchar> test_data(new guchar[pickle.size()]);
+ memcpy(test_data.get(), pickle.data(), pickle.size());
+ data.data = test_data.get();
+ data.length = pickle.size();
+
+ GURL url;
+ string16 title;
+ EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
+}
+
+TEST(GtkDndUtilTest, ExtractNamedURLInvalidInput) {
+ GURL url;
+ string16 title;
+ GtkSelectionData data;
+ data.data = NULL;
+ data.length = 0;
+
+ EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
+
+ guchar empty_data[] = "";
+ data.data = empty_data;
+ data.length = 0;
+
+ EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
+
+ const std::string kTitle = "title";
+ Pickle pickle;
+ pickle.WriteString(kTitle);
+
+ scoped_array<guchar> test_data(new guchar[pickle.size()]);
+ memcpy(test_data.get(), pickle.data(), pickle.size());
+ data.data = test_data.get();
+ data.length = pickle.size();
+
+ EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
+}
+
+} // namespace ui
diff --git a/ui/base/dragdrop/os_exchange_data.h b/ui/base/dragdrop/os_exchange_data.h
index c04737d..452252e 100644
--- a/ui/base/dragdrop/os_exchange_data.h
+++ b/ui/base/dragdrop/os_exchange_data.h
@@ -17,10 +17,10 @@
#include <gtk/gtk.h>
#endif
-#include "app/download_file_interface.h"
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/scoped_ptr.h"
+#include "ui/base/dragdrop/download_file_interface.h"
class GURL;
class Pickle;
diff --git a/ui/base/dragdrop/os_exchange_data_provider_gtk.cc b/ui/base/dragdrop/os_exchange_data_provider_gtk.cc
index 83bd600..892bd48 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_gtk.cc
+++ b/ui/base/dragdrop/os_exchange_data_provider_gtk.cc
@@ -6,10 +6,10 @@
#include <algorithm>
-#include "app/gtk_dnd_util.h"
#include "base/file_path.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_util.h"
+#include "ui/base/dragdrop/gtk_dnd_util.h"
namespace ui {
@@ -56,7 +56,7 @@ GtkTargetList* OSExchangeDataProviderGtk::GetTargetList() const {
gtk_target_list_add_uri_targets(targets, OSExchangeData::URL);
gtk_target_list_add(
targets,
- gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_NAMED_URL),
+ ui::GetAtomForTarget(ui::CHROME_NAMED_URL),
0,
OSExchangeData::URL);
}
@@ -90,7 +90,7 @@ void OSExchangeDataProviderGtk::WriteFormatToSelection(
pickle.WriteString(url_.spec());
gtk_selection_data_set(
selection,
- gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_NAMED_URL),
+ ui::GetAtomForTarget(ui::CHROME_NAMED_URL),
8,
reinterpret_cast<const guchar*>(pickle.data()),
pickle.size());