summaryrefslogtreecommitdiffstats
path: root/ui/views
diff options
context:
space:
mode:
Diffstat (limited to 'ui/views')
-rw-r--r--ui/views/controls/textfield/native_textfield_views_unittest.cc36
-rw-r--r--ui/views/views.gyp1
-rw-r--r--ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc649
-rw-r--r--ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h99
-rw-r--r--ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc20
-rw-r--r--ui/views/widget/desktop_aura/desktop_root_window_host_x11.h9
-rw-r--r--ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc4
-rw-r--r--ui/views/widget/desktop_aura/x11_desktop_window_move_client.h1
-rw-r--r--ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc3
-rw-r--r--ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h3
10 files changed, 671 insertions, 154 deletions
diff --git a/ui/views/controls/textfield/native_textfield_views_unittest.cc b/ui/views/controls/textfield/native_textfield_views_unittest.cc
index 2af45cc..56cd1d6 100644
--- a/ui/views/controls/textfield/native_textfield_views_unittest.cc
+++ b/ui/views/controls/textfield/native_textfield_views_unittest.cc
@@ -934,14 +934,7 @@ TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) {
}
#endif
-// TODO(erg): Disabled while the other half of drag and drop is being written.
-// http://crbug.com/130806
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#define MAYBE_DragAndDrop_InitiateDrag DISABLED_DragAndDrop_InitiateDrag
-#else
-#define MAYBE_DragAndDrop_InitiateDrag DragAndDrop_InitiateDrag
-#endif
-TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_InitiateDrag) {
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_InitiateDrag) {
InitTextfield(Textfield::STYLE_DEFAULT);
textfield_->SetText(ASCIIToUTF16("hello string world"));
@@ -987,14 +980,7 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_InitiateDrag) {
textfield_view_->GetDragOperationsForView(textfield_view_, kStringPoint));
}
-// TODO(erg): Disabled while the other half of drag and drop is being written.
-// http://crbug.com/130806
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#define MAYBE_DragAndDrop_ToTheRight DISABLED_DragAndDrop_ToTheRight
-#else
-#define MAYBE_DragAndDrop_ToTheRight DragAndDrop_ToTheRight
-#endif
-TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_ToTheRight) {
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) {
InitTextfield(Textfield::STYLE_DEFAULT);
textfield_->SetText(ASCIIToUTF16("hello world"));
@@ -1049,14 +1035,7 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_ToTheRight) {
EXPECT_STR_EQ("h welloorld", textfield_->text());
}
-// TODO(erg): Disabled while the other half of drag and drop is being written.
-// http://crbug.com/130806
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#define MAYBE_DragAndDrop_ToTheLeft DISABLED_DragAndDrop_ToTheLeft
-#else
-#define MAYBE_DragAndDrop_ToTheLeft DragAndDrop_ToTheLeft
-#endif
-TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_ToTheLeft) {
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) {
InitTextfield(Textfield::STYLE_DEFAULT);
textfield_->SetText(ASCIIToUTF16("hello world"));
@@ -1111,14 +1090,7 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_ToTheLeft) {
EXPECT_STR_EQ("h worlellod", textfield_->text());
}
-// TODO(erg): Disabled while the other half of drag and drop is being written.
-// http://crbug.com/130806
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#define MAYBE_DragAndDrop_Canceled DISABLED_DragAndDrop_Canceled
-#else
-#define MAYBE_DragAndDrop_Canceled DragAndDrop_Canceled
-#endif
-TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_Canceled) {
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_Canceled) {
InitTextfield(Textfield::STYLE_DEFAULT);
textfield_->SetText(ASCIIToUTF16("hello world"));
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 318f8db..4022df3 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -532,6 +532,7 @@
}],
['use_aura==1 and OS=="linux" and chromeos==0', {
'dependencies': [
+ '../ui.gyp:shell_dialogs',
'../linux_ui/linux_ui.gyp:linux_ui',
],
}],
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index ef2d6f8..004c19c 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -16,6 +16,7 @@
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
#include "ui/base/events/event.h"
+#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
@@ -24,11 +25,20 @@ using ui::OSExchangeData;
namespace {
+const int kMinXdndVersion = 5;
+
+const int kWillAcceptDrop = 1;
+const int kWantFurtherPosEvents = 2;
+
const char kXdndActionCopy[] = "XdndActionCopy";
const char kXdndActionMove[] = "XdndActionMove";
const char kXdndActionLink[] = "XdndActionLink";
+const char kChromiumDragReciever[] = "_CHROMIUM_DRAG_RECEIVER";
+const char kXdndSelection[] = "XdndSelection";
+
const char* kAtomsToCache[] = {
+ kChromiumDragReciever,
"XdndActionAsk",
kXdndActionCopy,
kXdndActionLink,
@@ -42,24 +52,117 @@ const char* kAtomsToCache[] = {
"XdndLeave",
"XdndPosition",
"XdndProxy", // Proxy windows?
- "XdndSelection",
+ kXdndSelection,
"XdndStatus",
"XdndTypeList",
NULL
};
+// Helper class to FindWindowFor which looks for a drag target under the
+// cursor.
+class DragTargetWindowFinder : public ui::EnumerateWindowsDelegate {
+ public:
+ DragTargetWindowFinder(XID ignored_icon_window,
+ gfx::Point screen_loc)
+ : ignored_icon_window_(ignored_icon_window),
+ output_window_(None),
+ screen_loc_(screen_loc) {
+ ui::EnumerateTopLevelWindows(this);
+ }
+
+ virtual ~DragTargetWindowFinder() {}
+
+ XID window() const { return output_window_; }
+
+ protected:
+ virtual bool ShouldStopIterating(XID window) OVERRIDE {
+ if (window == ignored_icon_window_)
+ return false;
+
+ if (!ui::IsWindowVisible(window))
+ return false;
+
+ if (!ui::WindowContainsPoint(window, screen_loc_))
+ return false;
+
+ if (ui::PropertyExists(window, "WM_STATE")) {
+ output_window_ = window;
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ XID ignored_icon_window_;
+ XID output_window_;
+ gfx::Point screen_loc_;
+
+ DISALLOW_COPY_AND_ASSIGN(DragTargetWindowFinder);
+};
+
+// Returns the topmost X11 window at |screen_point| if it is advertising that
+// is supports the Xdnd protocol. Will return the window under the pointer as
+// |mouse_window|. If there's a Xdnd aware window, it will be returned in
+// |dest_window|.
+void FindWindowFor(const gfx::Point& screen_point,
+ ::Window* mouse_window, ::Window* dest_window) {
+ DragTargetWindowFinder finder(None, screen_point);
+ *mouse_window = finder.window();
+ *dest_window = None;
+
+ if (finder.window() == None)
+ return;
+
+ // Figure out which window we should test as XdndAware. If mouse_window has
+ // XdndProxy, it will set that proxy on target, and if not, |target|'s
+ // original value will remain.
+ XID target = *mouse_window;
+ ui::GetXIDProperty(*mouse_window, "XdndProxy", &target);
+
+ int version;
+ if (ui::GetIntProperty(target, "XdndAware", &version) &&
+ version >= kMinXdndVersion) {
+ *dest_window = target;
+ }
+}
+
} // namespace
namespace views {
+std::map< ::Window, DesktopDragDropClientAuraX11*>
+ DesktopDragDropClientAuraX11::g_live_client_map;
+
class DesktopDragDropClientAuraX11::X11DragContext :
public base::MessageLoop::Dispatcher {
public:
X11DragContext(ui::X11AtomCache* atom_cache,
+ ::Window local_window,
const XClientMessageEvent& event);
virtual ~X11DragContext();
- const std::vector<Atom>& targets() { return targets_; }
+ // When we receive an XdndPosition message, we need to have all the data
+ // copied from the other window before we process the XdndPosition
+ // message. If we have that data already, dispatch immediately. Otherwise,
+ // delay dispatching until we do.
+ void OnStartXdndPositionMessage(DesktopDragDropClientAuraX11* client,
+ ::Window source_window,
+ const gfx::Point& screen_point);
+
+ // Called to request the next target from the source window. This is only
+ // done on the first XdndPosition; after that, we cache the data offered by
+ // the source window.
+ void RequestNextTarget();
+
+ // Called when XSelection data has been copied to our process.
+ void OnSelectionNotify(const XSelectionEvent& xselection);
+
+ // Clones the fetched targets.
+ scoped_ptr<ui::SelectionFormatMap> CloneFetchedTargets() {
+ DCHECK(fetched_targets_);
+ return fetched_targets_->Clone();
+ }
// Reads the "XdndActionList" property from |source_window| and copies it
// into |actions|.
@@ -76,13 +179,30 @@ class DesktopDragDropClientAuraX11::X11DragContext :
// The atom cache owned by our parent.
ui::X11AtomCache* atom_cache_;
+ // The XID of our chrome local aura window handling our events.
+ ::Window local_window_;
+
// The XID of the window that's initiated the drag.
unsigned long source_window_;
- // targets.
- std::vector<Atom> targets_;
+ // The client we inform once we're done with requesting data.
+ DesktopDragDropClientAuraX11* drag_drop_client_;
+
+ // Whether we're blocking the handling of an XdndPosition message by waiting
+ // for |unfetched_targets_| to be fetched.
+ bool waiting_to_handle_position_;
+
+ // Where the cursor is on screen.
+ gfx::Point screen_point_;
- // supplied actions
+ // A SelectionFormatMap of data that we have in our process.
+ scoped_ptr<ui::SelectionFormatMap> fetched_targets_;
+
+ // The names of various data types offered by the other window that we
+ // haven't fetched and put in |fetched_targets_| yet.
+ std::vector<Atom> unfetched_targets_;
+
+ // Possible actions.
std::vector<Atom> actions_;
DISALLOW_COPY_AND_ASSIGN(X11DragContext);
@@ -90,60 +210,139 @@ class DesktopDragDropClientAuraX11::X11DragContext :
DesktopDragDropClientAuraX11::X11DragContext::X11DragContext(
ui::X11AtomCache* atom_cache,
+ ::Window local_window,
const XClientMessageEvent& event)
: atom_cache_(atom_cache),
- source_window_(event.data.l[0]) {
+ local_window_(local_window),
+ source_window_(event.data.l[0]),
+ drag_drop_client_(NULL),
+ waiting_to_handle_position_(false) {
bool get_types = ((event.data.l[1] & 1) != 0);
if (get_types) {
if (!ui::GetAtomArrayProperty(source_window_,
"XdndTypeList",
- &targets_)) {
+ &unfetched_targets_)) {
return;
}
} else {
// data.l[2,3,4] contain the first three types. Unused slots can be None.
for (int i = 0; i < 3; ++i) {
if (event.data.l[2+i] != None) {
- targets_.push_back(event.data.l[2+i]);
+ unfetched_targets_.push_back(event.data.l[2+i]);
}
}
}
- // TODO(erg): If this window is part of our process, don't listen through the
- // MessagePump, but instead listen to the DesktopDragDropClientAuraX11
- // associated with that window.
- base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(
- this, source_window_);
- XSelectInput(base::MessagePumpAuraX11::GetDefaultXDisplay(),
- source_window_, PropertyChangeMask);
-
- // We must perform a full sync here because we could be racing
- // |source_window_|.
- XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), False);
+ DesktopDragDropClientAuraX11* client =
+ DesktopDragDropClientAuraX11::GetForWindow(source_window_);
+ if (!client) {
+ // The window doesn't have a DesktopDragDropClientAuraX11, that means it's
+ // created by some other process. Listen for messages on it.
+ base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(
+ this, source_window_);
+ XSelectInput(base::MessagePumpAuraX11::GetDefaultXDisplay(),
+ source_window_, PropertyChangeMask);
+
+ // We must perform a full sync here because we could be racing
+ // |source_window_|.
+ XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), False);
+ } else {
+ // This drag originates from an aura window within our process. This means
+ // that we can shortcut the X11 server and ask the owning SelectionOwner
+ // for the data it's offering.
+ fetched_targets_ = client->CloneFormatMap();
+ unfetched_targets_.clear();
+ }
ReadActions();
}
DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() {
- // Unsubscribe to message events.
- base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(
- source_window_);
+ DesktopDragDropClientAuraX11* client =
+ DesktopDragDropClientAuraX11::GetForWindow(source_window_);
+ if (!client) {
+ // Unsubscribe from message events.
+ base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(
+ source_window_);
+ }
}
-void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() {
- std::vector<Atom> atom_array;
+void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage(
+ DesktopDragDropClientAuraX11* client,
+ ::Window source_window,
+ const gfx::Point& screen_point) {
+ DCHECK_EQ(source_window_, source_window);
+
+ if (!unfetched_targets_.empty()) {
+ // We have unfetched targets. That means we need to pause the handling of
+ // the position message and ask the other window for its data.
+ screen_point_ = screen_point;
+ drag_drop_client_ = client;
+ waiting_to_handle_position_ = true;
+
+ fetched_targets_.reset(new ui::SelectionFormatMap);
+ RequestNextTarget();
+ } else {
+ client->CompleteXdndPosition(source_window, screen_point);
+ }
+}
+
+void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() {
+ ::Atom target = unfetched_targets_.back();
+ unfetched_targets_.pop_back();
+
+ XConvertSelection(base::MessagePumpAuraX11::GetDefaultXDisplay(),
+ atom_cache_->GetAtom(kXdndSelection),
+ target,
+ atom_cache_->GetAtom(kChromiumDragReciever),
+ local_window_,
+ CurrentTime);
+}
+
+void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify(
+ const XSelectionEvent& event) {
+ DCHECK(waiting_to_handle_position_);
+ DCHECK(drag_drop_client_);
+ DCHECK_EQ(event.property, atom_cache_->GetAtom(kChromiumDragReciever));
+
+ unsigned char* data = NULL;
+ size_t data_bytes = 0;
+ ::Atom type = None;
+ if (ui::GetRawBytesOfProperty(local_window_, event.property,
+ &data, &data_bytes, NULL, &type)) {
+ char* copied_data = new char[data_bytes];
+ memcpy(copied_data, data, data_bytes);
+ fetched_targets_->Insert(event.target, copied_data, data_bytes);
+ XFree(data);
+ }
- // TODO(erg): The GTK+ code has a fast path that short circuits talking over
- // X11 for local windows. When we become a drop source, we should have a
- // similar fast path.
+ if (!unfetched_targets_.empty()) {
+ RequestNextTarget();
+ } else {
+ waiting_to_handle_position_ = false;
+ drag_drop_client_->CompleteXdndPosition(source_window_, screen_point_);
+ drag_drop_client_ = NULL;
+ }
+}
- if (!ui::GetAtomArrayProperty(source_window_,
- "XdndActionList",
- &atom_array)) {
- actions_.clear();
+void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() {
+ DesktopDragDropClientAuraX11* client =
+ DesktopDragDropClientAuraX11::GetForWindow(source_window_);
+ if (!client) {
+ std::vector<Atom> atom_array;
+ if (!ui::GetAtomArrayProperty(source_window_,
+ "XdndActionList",
+ &atom_array)) {
+ actions_.clear();
+ } else {
+ actions_.swap(atom_array);
+ }
} else {
- actions_.swap(atom_array);
+ // We have a property notify set up for other windows in case they change
+ // their action list. Thankfully, the views interface is static and you
+ // can't change the action list after you enter StartDragAndDrop().
+ actions_ = client->GetOfferedDragOperations();
}
}
@@ -178,22 +377,40 @@ DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
aura::RootWindow* root_window,
Display* xdisplay,
::Window xwindow)
- : root_window_host_(root_window_host),
+ : move_loop_(this),
+ root_window_host_(root_window_host),
root_window_(root_window),
xdisplay_(xdisplay),
xwindow_(xwindow),
atom_cache_(xdisplay_, kAtomsToCache),
target_window_(NULL),
+ source_provider_(NULL),
+ source_current_window_(None),
drag_drop_in_progress_(false),
- drag_operation_(0) {
+ drag_operation_(0),
+ resulting_operation_(0) {
+ DCHECK(g_live_client_map.find(xwindow) == g_live_client_map.end());
+ g_live_client_map.insert(std::make_pair(xwindow, this));
+
// Mark that we are aware of drag and drop concepts.
- unsigned long xdnd_version = 5;
+ unsigned long xdnd_version = kMinXdndVersion;
XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"),
XA_ATOM, 32, PropModeReplace,
reinterpret_cast<unsigned char*>(&xdnd_version), 1);
}
DesktopDragDropClientAuraX11::~DesktopDragDropClientAuraX11() {
+ g_live_client_map.erase(xwindow_);
+}
+
+// static
+DesktopDragDropClientAuraX11* DesktopDragDropClientAuraX11::GetForWindow(
+ ::Window window) {
+ std::map< ::Window, DesktopDragDropClientAuraX11*>::const_iterator it =
+ g_live_client_map.find(window);
+ if (it == g_live_client_map.end())
+ return NULL;
+ return it->second;
}
void DesktopDragDropClientAuraX11::OnXdndEnter(
@@ -207,8 +424,9 @@ void DesktopDragDropClientAuraX11::OnXdndEnter(
}
// Make sure that we've run ~X11DragContext() before creating another one.
- current_context_.reset();
- current_context_.reset(new X11DragContext(&atom_cache_, event));
+ target_current_context_.reset();
+ target_current_context_.reset(
+ new X11DragContext(&atom_cache_, xwindow_, event));
// In the Windows implementation, we immediately call DesktopDropTargetWin::
// Translate(). Here, we wait until we receive an XdndPosition message
@@ -218,8 +436,9 @@ void DesktopDragDropClientAuraX11::OnXdndEnter(
void DesktopDragDropClientAuraX11::OnXdndLeave(
const XClientMessageEvent& event) {
+ DVLOG(1) << "XdndLeave";
NotifyDragLeave();
- current_context_.reset();
+ target_current_context_.reset();
}
void DesktopDragDropClientAuraX11::OnXdndPosition(
@@ -230,48 +449,60 @@ void DesktopDragDropClientAuraX11::OnXdndPosition(
int x_root_window = event.data.l[2] >> 16;
int y_root_window = event.data.l[2] & 0xffff;
- if (!current_context_.get()) {
+ if (!target_current_context_.get()) {
NOTREACHED();
return;
}
- int drag_operation = ui::DragDropTypes::DRAG_NONE;
- scoped_ptr<ui::OSExchangeData> data;
- scoped_ptr<ui::DropTargetEvent> drop_target_event;
- DragDropDelegate* delegate;
- DragTranslate(gfx::Point(x_root_window, y_root_window),
- &data, &drop_target_event, &delegate);
- if (delegate)
- drag_operation = delegate->OnDragUpdated(*drop_target_event);
-
- // Sends an XdndStatus message back to the source_window. l[2,3]
- // theoretically represent an area in the window where the current action is
- // the same as what we're returning, but I can't find any implementation that
- // actually making use of this. A client can return (0, 0) and/or set the
- // first bit of l[1] to disable the feature, and it appears that gtk neither
- // sets this nor respects it if set.
- XEvent xev;
- xev.xclient.type = ClientMessage;
- xev.xclient.message_type = atom_cache_.GetAtom("XdndStatus");
- xev.xclient.format = 32;
- xev.xclient.window = source_window;
- xev.xclient.data.l[0] = xwindow_;
- xev.xclient.data.l[1] = (drag_operation != 0) ? (2 | 1) : 0;
- xev.xclient.data.l[2] = 0;
- xev.xclient.data.l[3] = 0;
- xev.xclient.data.l[4] = DragOperationToAtom(drag_operation);
-
- SendXClientEvent(source_window, &xev);
+ // If we already have all the data from this drag, we complete it
+ // immediately.
+ target_current_context_->OnStartXdndPositionMessage(
+ this, source_window, gfx::Point(x_root_window, y_root_window));
}
void DesktopDragDropClientAuraX11::OnXdndStatus(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndStatus";
+
+ unsigned long source_window = event.data.l[0];
+ if (event.data.l[1] & 1)
+ negotiated_operation_[source_window] = event.data.l[4];
+
+ // Note: event.data.[2,3] specify a rectangle. It is a request by the other
+ // window to not send further XdndPosition messages while the cursor is
+ // within it. However, it is considered advisory and (at least according to
+ // the spec) the other side must handle further position messages within
+ // it. GTK+ doesn't bother with this, so neither should we.
+
+ waiting_on_status_.erase(source_window);
+
+ // TODO(erg): We should be using the response to try to update the cursor or
+ // something.
+
+ if (ContainsKey(pending_drop_, source_window)) {
+ // We were waiting on the status message so we could send the XdndDrop.
+ SendXdndDrop(source_window);
+ return;
+ }
+
+ NextPositionMap::iterator it = next_position_message_.find(source_window);
+ if (it != next_position_message_.end()) {
+ // We were waiting on the status message so we could send off the next
+ // position message we queued up.
+ gfx::Point p = it->second.first;
+ unsigned long time = it->second.second;
+ next_position_message_.erase(it);
+
+ SendXdndPosition(source_window, p, time);
+ }
}
void DesktopDragDropClientAuraX11::OnXdndFinished(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndFinished";
+ resulting_operation_ = AtomToDragOperation(
+ negotiated_operation_[event.data.l[0]]);
+ move_loop_.EndMoveLoop();
}
void DesktopDragDropClientAuraX11::OnXdndDrop(
@@ -286,11 +517,12 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
aura::client::GetDragDropDelegate(target_window_);
if (delegate) {
ui::OSExchangeData data(new ui::OSExchangeDataProviderAuraX11(
- root_window_host_, xwindow_, current_context_->targets()));
+ xwindow_, target_current_context_->CloneFetchedTargets()));
+
ui::DropTargetEvent event(data,
target_window_location_,
target_window_root_location_,
- current_context_->GetDragOperation());
+ target_current_context_->GetDragOperation());
drag_operation = delegate->OnPerformDrop(event);
}
@@ -310,6 +542,16 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
SendXClientEvent(source_window, &xev);
}
+void DesktopDragDropClientAuraX11::OnSelectionNotify(
+ const XSelectionEvent& xselection) {
+ if (!target_current_context_) {
+ NOTIMPLEMENTED();
+ return;
+ }
+
+ target_current_context_->OnSelectionNotify(xselection);
+}
+
int DesktopDragDropClientAuraX11::StartDragAndDrop(
const ui::OSExchangeData& data,
aura::RootWindow* root_window,
@@ -317,16 +559,31 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
const gfx::Point& root_location,
int operation,
ui::DragDropTypes::DragEventSource source) {
+ source_current_window_ = None;
+ drag_drop_in_progress_ = true;
+ drag_operation_ = operation;
+ resulting_operation_ = ui::DragDropTypes::DRAG_NONE;
+
+ const ui::OSExchangeData::Provider* provider = &data.provider();
+ source_provider_ = static_cast<const ui::OSExchangeDataProviderAuraX11*>(
+ provider);
+
+ source_provider_->TakeOwnershipOfSelection();
+
+ std::vector< ::Atom> actions = GetOfferedDragOperations();
+ ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions);
+
// Windows has a specific method, DoDragDrop(), which performs the entire
// drag. We have to emulate this, so we spin off a nested runloop which will
// track all cursor movement and reroute events to a specific handler.
+ move_loop_.RunMoveLoop(source_window);
- NOTIMPLEMENTED();
-
- // TODO(erg): Once this is implemented, make sure to reenable the
- // NativeTextfieldViewsTest_DragAndDrop* tests.
+ source_provider_ = NULL;
+ drag_drop_in_progress_ = false;
+ drag_operation_ = 0;
+ XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList"));
- return ui::DragDropTypes::DRAG_NONE;
+ return resulting_operation_;
}
void DesktopDragDropClientAuraX11::DragUpdate(aura::Window* target,
@@ -340,7 +597,7 @@ void DesktopDragDropClientAuraX11::Drop(aura::Window* target,
}
void DesktopDragDropClientAuraX11::DragCancel() {
- NOTIMPLEMENTED();
+ move_loop_.EndMoveLoop();
}
bool DesktopDragDropClientAuraX11::IsDragDropInProgress() {
@@ -352,6 +609,64 @@ void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) {
target_window_ = NULL;
}
+void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) {
+ gfx::Point screen_point(event->x_root, event->y_root);
+
+ // Find the current window the cursor is over.
+ ::Window mouse_window = None;
+ ::Window dest_window = None;
+ FindWindowFor(screen_point, &mouse_window, &dest_window);
+
+ if (source_current_window_ != dest_window) {
+ if (source_current_window_ != None)
+ SendXdndLeave(source_current_window_);
+
+ source_current_window_ = dest_window;
+
+ if (source_current_window_ != None) {
+ negotiated_operation_.erase(source_current_window_);
+ SendXdndEnter(source_current_window_);
+ }
+ }
+
+ if (source_current_window_ != None) {
+ if (ContainsKey(waiting_on_status_, dest_window)) {
+ next_position_message_[dest_window] =
+ std::make_pair(screen_point, event->time);
+ } else {
+ SendXdndPosition(dest_window, screen_point, event->time);
+ }
+ }
+}
+
+void DesktopDragDropClientAuraX11::OnMouseReleased() {
+ if (source_current_window_ != None) {
+ if (ContainsKey(waiting_on_status_, source_current_window_)) {
+ // If we are waiting for an XdndStatus message, we need to wait for it to
+ // complete.
+ pending_drop_.insert(source_current_window_);
+ return;
+ }
+
+ std::map< ::Window, ::Atom>::iterator it =
+ negotiated_operation_.find(source_current_window_);
+ if (it != negotiated_operation_.end() && it->second != None) {
+ // We have negotiated an action with the other end.
+ SendXdndDrop(source_current_window_);
+ return;
+ }
+
+ SendXdndLeave(source_current_window_);
+ source_current_window_ = None;
+ }
+
+ move_loop_.EndMoveLoop();
+}
+
+void DesktopDragDropClientAuraX11::OnMoveLoopEnded() {
+ target_current_context_.reset();
+}
+
void DesktopDragDropClientAuraX11::DragTranslate(
const gfx::Point& root_window_location,
scoped_ptr<ui::OSExchangeData>* data,
@@ -378,7 +693,7 @@ void DesktopDragDropClientAuraX11::DragTranslate(
return;
data->reset(new OSExchangeData(new ui::OSExchangeDataProviderAuraX11(
- root_window_host_, xwindow_, current_context_->targets())));
+ xwindow_, target_current_context_->CloneFetchedTargets())));
gfx::Point location = root_location;
aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
@@ -389,7 +704,7 @@ void DesktopDragDropClientAuraX11::DragTranslate(
*(data->get()),
location,
root_location,
- current_context_->GetDragOperation()));
+ target_current_context_->GetDragOperation()));
if (target_window_changed)
(*delegate)->OnDragEntered(*event->get());
}
@@ -405,7 +720,7 @@ void DesktopDragDropClientAuraX11::NotifyDragLeave() {
target_window_ = NULL;
}
-unsigned long DesktopDragDropClientAuraX11::DragOperationToAtom(
+::Atom DesktopDragDropClientAuraX11::DragOperationToAtom(
int drag_operation) {
if (drag_operation & ui::DragDropTypes::DRAG_COPY)
return atom_cache_.GetAtom(kXdndActionCopy);
@@ -417,24 +732,184 @@ unsigned long DesktopDragDropClientAuraX11::DragOperationToAtom(
return None;
}
-void DesktopDragDropClientAuraX11::SendXClientEvent(unsigned long xid,
+int DesktopDragDropClientAuraX11::AtomToDragOperation(::Atom atom) {
+ if (atom == atom_cache_.GetAtom(kXdndActionCopy))
+ return ui::DragDropTypes::DRAG_COPY;
+ if (atom == atom_cache_.GetAtom(kXdndActionMove))
+ return ui::DragDropTypes::DRAG_MOVE;
+ if (atom == atom_cache_.GetAtom(kXdndActionLink))
+ return ui::DragDropTypes::DRAG_LINK;
+
+ return ui::DragDropTypes::DRAG_NONE;
+}
+
+std::vector< ::Atom> DesktopDragDropClientAuraX11::GetOfferedDragOperations() {
+ std::vector< ::Atom> operations;
+ if (drag_operation_ & ui::DragDropTypes::DRAG_COPY)
+ operations.push_back(atom_cache_.GetAtom(kXdndActionCopy));
+ if (drag_operation_ & ui::DragDropTypes::DRAG_MOVE)
+ operations.push_back(atom_cache_.GetAtom(kXdndActionMove));
+ if (drag_operation_ & ui::DragDropTypes::DRAG_LINK)
+ operations.push_back(atom_cache_.GetAtom(kXdndActionLink));
+ return operations;
+}
+
+scoped_ptr<ui::SelectionFormatMap>
+DesktopDragDropClientAuraX11::CloneFormatMap() const {
+ return source_provider_ ? source_provider_->CloneFormatMap() :
+ scoped_ptr<ui::SelectionFormatMap>();
+}
+
+void DesktopDragDropClientAuraX11::CompleteXdndPosition(
+ ::Window source_window,
+ const gfx::Point& screen_point) {
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ scoped_ptr<ui::OSExchangeData> data;
+ scoped_ptr<ui::DropTargetEvent> drop_target_event;
+ DragDropDelegate* delegate = NULL;
+ DragTranslate(screen_point, &data, &drop_target_event, &delegate);
+ if (delegate)
+ drag_operation = delegate->OnDragUpdated(*drop_target_event);
+
+ // Sends an XdndStatus message back to the source_window. l[2,3]
+ // theoretically represent an area in the window where the current action is
+ // the same as what we're returning, but I can't find any implementation that
+ // actually making use of this. A client can return (0, 0) and/or set the
+ // first bit of l[1] to disable the feature, and it appears that gtk neither
+ // sets this nor respects it if set.
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndStatus");
+ xev.xclient.format = 32;
+ xev.xclient.window = source_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = (drag_operation != 0) ?
+ (kWantFurtherPosEvents | kWillAcceptDrop) : 0;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = DragOperationToAtom(drag_operation);
+
+ SendXClientEvent(source_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) {
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndEnter");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = (kMinXdndVersion << 24); // The version number.
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ std::vector<Atom> targets;
+ source_provider_->RetrieveTargets(&targets);
+
+ if (targets.size() > 3) {
+ xev.xclient.data.l[1] |= 1;
+ ui::SetAtomArrayProperty(xwindow_, "XdndTypeList", "ATOM", targets);
+ } else {
+ // Pack the targets into the enter message.
+ for (size_t i = 0; i < targets.size(); ++i)
+ xev.xclient.data.l[2 + i] = targets[i];
+ }
+
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndLeave(::Window dest_window) {
+ // If we're sending a leave message, don't wait for status messages anymore.
+ waiting_on_status_.erase(dest_window);
+ NextPositionMap::iterator it = next_position_message_.find(dest_window);
+ if (it != next_position_message_.end())
+ next_position_message_.erase(it);
+
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndLeave");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndPosition(
+ ::Window dest_window,
+ const gfx::Point& screen_point,
+ unsigned long time) {
+ waiting_on_status_.insert(dest_window);
+
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndPosition");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = (screen_point.x() << 16) | screen_point.y();
+ xev.xclient.data.l[3] = time;
+ xev.xclient.data.l[4] = DragOperationToAtom(drag_operation_);
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) {
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom_cache_.GetAtom("XdndDrop");
+ xev.xclient.format = 32;
+ xev.xclient.window = dest_window;
+ xev.xclient.data.l[0] = xwindow_;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = CurrentTime;
+ xev.xclient.data.l[3] = None;
+ xev.xclient.data.l[4] = None;
+ SendXClientEvent(dest_window, &xev);
+}
+
+void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid,
XEvent* xev) {
DCHECK_EQ(ClientMessage, xev->type);
- // TODO(erg): When I get drag receiving working, shortcut messages to the X
- // server and call the receivers DesktopDragDropClientAuraX11 instance
- // instead.
- //
+ // Don't send messages to the X11 message queue if we can help it.
+ DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid);
+ if (short_circuit) {
+ Atom message_type = xev->xclient.message_type;
+ if (message_type == atom_cache_.GetAtom("XdndEnter")) {
+ short_circuit->OnXdndEnter(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
+ short_circuit->OnXdndLeave(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
+ short_circuit->OnXdndPosition(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
+ short_circuit->OnXdndStatus(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
+ short_circuit->OnXdndFinished(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
+ short_circuit->OnXdndDrop(xev->xclient);
+ return;
+ }
+ }
+
// I don't understand why the GTK+ code is doing what it's doing here. It
// goes out of its way to send the XEvent so that it receives a callback on
- // success or failure, and when it fails, it then sends an internal GdkEvent
- // about the failed drag. (And sending this message doesn't appear to go
- // through normal xlib machinery, but instead passes through the low level
- // xProto (the x11 wire format) that I don't understand.
+ // success or failure, and when it fails, it then sends an internal
+ // GdkEvent about the failed drag. (And sending this message doesn't appear
+ // to go through normal xlib machinery, but instead passes through the low
+ // level xProto (the x11 wire format) that I don't understand.
//
// I'm unsure if I have to jump through those hoops, or if XSendEvent is
// sufficient.
-
XSendEvent(xdisplay_, xid, False, 0, xev);
}
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
index 47c4f2b..4152778 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -10,6 +10,8 @@
// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
#undef RootWindow
+#include <set>
+
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -18,6 +20,8 @@
#include "ui/base/x/x11_atom_cache.h"
#include "ui/gfx/point.h"
#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
+#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
namespace aura {
class RootWindow;
@@ -34,7 +38,9 @@ namespace ui {
class DragSource;
class DropTargetEvent;
class OSExchangeData;
+class OSExchangeDataProviderAuraX11;
class RootWindow;
+class SelectionFormatMap;
}
namespace views {
@@ -45,7 +51,8 @@ class DesktopRootWindowHostX11;
// handles the views drag events.
class VIEWS_EXPORT DesktopDragDropClientAuraX11
: public aura::client::DragDropClient,
- public aura::WindowObserver {
+ public aura::WindowObserver,
+ public X11WholeScreenMoveLoopDelegate {
public:
DesktopDragDropClientAuraX11(
views::DesktopRootWindowHostX11* root_window_host,
@@ -54,6 +61,11 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
::Window xwindow);
virtual ~DesktopDragDropClientAuraX11();
+ // We maintain a mapping of live DesktopDragDropClientAuraX11 objects to
+ // their ::Windows. We do this so that we're able to short circuit sending
+ // X11 messages to windows in our process.
+ static DesktopDragDropClientAuraX11* GetForWindow(::Window window);
+
// These methods handle the various X11 client messages from the platform.
void OnXdndEnter(const XClientMessageEvent& event);
void OnXdndLeave(const XClientMessageEvent& event);
@@ -62,6 +74,9 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
void OnXdndFinished(const XClientMessageEvent& event);
void OnXdndDrop(const XClientMessageEvent& event);
+ // Called when XSelection data has been copied to our process.
+ void OnSelectionNotify(const XSelectionEvent& xselection);
+
// Overridden from aura::client::DragDropClient:
virtual int StartDragAndDrop(
const ui::OSExchangeData& data,
@@ -77,10 +92,18 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
virtual void DragCancel() OVERRIDE;
virtual bool IsDragDropInProgress() OVERRIDE;
- // aura::WindowObserver implementation:
+ // Overridden from aura::WindowObserver:
virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+ // Overridden from X11WholeScreenMoveLoopDelegate:
+ virtual void OnMouseMovement(XMotionEvent* event) OVERRIDE;
+ virtual void OnMouseReleased() OVERRIDE;
+ virtual void OnMoveLoopEnded() OVERRIDE;
+
private:
+ typedef std::map< ::Window, std::pair<gfx::Point, unsigned long> >
+ NextPositionMap;
+
// When we receive an position x11 message, we need to translate that into
// the underlying aura::Window representation, as moves internal to the X11
// window can cause internal drag leave and enter messages.
@@ -95,11 +118,41 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
// Converts our bitfield of actions into an Atom that represents what action
// we're most likely to take on drop.
- unsigned long DragOperationToAtom(int drag_operation);
+ ::Atom DragOperationToAtom(int drag_operation);
+
+ // Converts a single action atom to a drag operation.
+ int AtomToDragOperation(::Atom atom);
+
+ // During the blocking StartDragAndDrop() call, this converts the views-style
+ // |drag_operation_| bitfield into a vector of Atoms to offer to other
+ // processes.
+ std::vector< ::Atom> GetOfferedDragOperations();
+
+ // This returns a newly allocated copy of the data we're offering in this
+ // drag. This is done to bypass an asynchronous roundtrip with the X11
+ // server.
+ scoped_ptr<ui::SelectionFormatMap> CloneFormatMap() const;
+
+ // Handling XdndPosition can be paused while waiting for more data; this is
+ // called either synchronously from OnXdndPosition, or asynchronously after
+ // we've received data requested from the other window.
+ void CompleteXdndPosition(::Window source_window,
+ const gfx::Point& screen_point);
+
+ void SendXdndEnter(::Window dest_window);
+ void SendXdndLeave(::Window dest_window);
+ void SendXdndPosition(::Window dest_window,
+ const gfx::Point& screen_point,
+ unsigned long time);
+ void SendXdndDrop(::Window dest_window);
// Sends |xev| to |xid|, optionally short circuiting the round trip to the X
// server.
- void SendXClientEvent(unsigned long xid, XEvent* xev);
+ void SendXClientEvent(::Window xid, XEvent* xev);
+
+ // A nested message loop that notifies this object of events through the
+ // X11WholeScreenMoveLoopDelegate interface.
+ X11WholeScreenMoveLoop move_loop_;
views::DesktopRootWindowHostX11* root_window_host_;
aura::RootWindow* root_window_;
@@ -110,9 +163,8 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
ui::X11AtomCache atom_cache_;
// Target side information.
-
class X11DragContext;
- scoped_ptr<X11DragContext> current_context_;
+ scoped_ptr<X11DragContext> target_current_context_;
// The Aura window that is currently under the cursor. We need to manually
// keep track of this because Windows will only call our drag enter method
@@ -127,10 +179,45 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
gfx::Point target_window_location_;
gfx::Point target_window_root_location_;
+ // In the Xdnd protocol, we aren't supposed to send another XdndPosition
+ // message until we have received a confirming XdndStatus message.
+ std::set< ::Window> waiting_on_status_;
+
+ // If we would send an XdndPosition message while we're waiting for an
+ // XdndStatus response, we need to cache the latest details we'd send.
+ NextPositionMap next_position_message_;
+
+ // Source side information.
+ ui::OSExchangeDataProviderAuraX11 const* source_provider_;
+ ::Window source_current_window_;
+
bool drag_drop_in_progress_;
+ // The operation bitfield as requested by StartDragAndDrop.
int drag_operation_;
+ // The operation performed. Is initialized to None at the start of
+ // StartDragAndDrop(), and is set only during the asynchronous XdndFinished
+ // message.
+ int resulting_operation_;
+
+ // This window will be receiving a drop as soon as we receive an XdndStatus
+ // from it.
+ std::set< ::Window> pending_drop_;
+
+ // We offer the other window a list of possible operations,
+ // XdndActionsList. This is the requested action from the other window. This
+ // is None if we haven't sent out an XdndPosition message yet, haven't yet
+ // received an XdndStatus or if the other window has told us that there's no
+ // action that we can agree on.
+ //
+ // This is a map instead of a simple variable because of the case where we
+ // put an XdndLeave in the queue at roughly the same time that the other
+ // window responds to an XdndStatus.
+ std::map< ::Window, ::Atom> negotiated_operation_;
+
+ static std::map< ::Window, DesktopDragDropClientAuraX11*> g_live_client_map;
+
DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11);
};
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
index 4606a6f..ea98a9c 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
@@ -111,8 +111,7 @@ DesktopRootWindowHostX11::DesktopRootWindowHostX11(
focus_when_shown_(false),
current_cursor_(ui::kCursorNull),
native_widget_delegate_(native_widget_delegate),
- desktop_native_widget_aura_(desktop_native_widget_aura),
- drop_handler_(NULL) {
+ desktop_native_widget_aura_(desktop_native_widget_aura) {
}
DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
@@ -907,20 +906,6 @@ void DesktopRootWindowHostX11::PrepareForShutdown() {
}
////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostX11, ui::DesktopSelectionProviderAuraX11 implementation:
-
-void DesktopRootWindowHostX11::SetDropHandler(
- ui::OSExchangeDataProviderAuraX11* handler) {
- if (handler) {
- DCHECK(!drop_handler_);
- drop_handler_ = handler;
- } else {
- DCHECK(drop_handler_);
- drop_handler_ = NULL;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
// DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation:
bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
@@ -1194,8 +1179,7 @@ bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
break;
}
case SelectionNotify: {
- if (drop_handler_)
- drop_handler_->OnSelectionNotify(xev->xselection);
+ drag_drop_client_->OnSelectionNotify(xev->xselection);
break;
}
}
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
index 8cd7aa3..ca178ba 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
@@ -15,7 +15,6 @@
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/root_window_host.h"
#include "ui/base/cursor/cursor_loader_x11.h"
-#include "ui/base/dragdrop/desktop_selection_provider_aurax11.h"
#include "ui/base/x/x11_atom_cache.h"
#include "ui/gfx/rect.h"
#include "ui/views/views_export.h"
@@ -43,7 +42,6 @@ class CursorManager;
class VIEWS_EXPORT DesktopRootWindowHostX11 :
public DesktopRootWindowHost,
public aura::RootWindowHost,
- public ui::DesktopSelectionProviderAuraX11,
public base::MessageLoop::Dispatcher {
public:
DesktopRootWindowHostX11(
@@ -172,10 +170,6 @@ class VIEWS_EXPORT DesktopRootWindowHostX11 :
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
virtual void PrepareForShutdown() OVERRIDE;
- // Overridden from DesktopSelectionProviderAuraX11:
- virtual void SetDropHandler(
- ui::OSExchangeDataProviderAuraX11* handler) OVERRIDE;
-
// Overridden from Dispatcher:
virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
@@ -230,9 +224,6 @@ class VIEWS_EXPORT DesktopRootWindowHostX11 :
aura::RootWindowHostDelegate* root_window_host_delegate_;
aura::Window* content_window_;
- // We forward drop related messages to this object.
- ui::OSExchangeDataProviderAuraX11* drop_handler_;
-
// The current root window host that has capture. While X11 has something
// like Windows SetCapture()/ReleaseCapture(), it is entirely implicit and
// there are no notifications when this changes. We need to track this so we
diff --git a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
index e90cb64..986e945 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
+++ b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
@@ -34,6 +34,10 @@ void X11DesktopWindowMoveClient::OnMouseMovement(XMotionEvent* event) {
system_loc, root_window_->GetHostSize()));
}
+void X11DesktopWindowMoveClient::OnMouseReleased() {
+ EndMoveLoop();
+}
+
void X11DesktopWindowMoveClient::OnMoveLoopEnded() {
root_window_ = NULL;
}
diff --git a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
index 0238a25..d4f2d8e 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
+++ b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
@@ -35,6 +35,7 @@ class VIEWS_EXPORT X11DesktopWindowMoveClient :
// Overridden from X11WholeScreenMoveLoopDelegate:
virtual void OnMouseMovement(XMotionEvent* event) OVERRIDE;
+ virtual void OnMouseReleased() OVERRIDE;
virtual void OnMoveLoopEnded() OVERRIDE;
// Overridden from aura::client::WindowMoveClient:
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index 7053432..9cdce13 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -43,9 +43,8 @@ bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) {
delegate_->OnMouseMovement(&xev->xmotion);
break;
}
- case ButtonPress:
case ButtonRelease: {
- EndMoveLoop();
+ delegate_->OnMouseReleased();
break;
}
}
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h
index f6a569c..69f63be 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h
@@ -18,6 +18,9 @@ class X11WholeScreenMoveLoopDelegate {
// Called when we receive a motion event.
virtual void OnMouseMovement(XMotionEvent* event) = 0;
+ // Called when the mouse button is released.
+ virtual void OnMouseReleased() = 0;
+
// Called when the user has released the mouse button. The move loop will
// release the grab after this has been called.
virtual void OnMoveLoopEnded() = 0;