Skip to content

Commit

Permalink
Add tests for drag and drop for Linux Aura
Browse files Browse the repository at this point in the history
This CL also adds handling for rejecting the drop in the XdndFinished message.

TEST=DesktopDragDropClientAuraX11Test.*
BUG=None

Review URL: https://codereview.chromium.org/285013002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270534 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
pkotwicz@chromium.org committed May 15, 2014
1 parent 266e019 commit 172e9f1
Show file tree
Hide file tree
Showing 4 changed files with 764 additions and 78 deletions.
1 change: 1 addition & 0 deletions ui/views/views.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@
'view_model_utils_unittest.cc',
'view_targeter_unittest.cc',
'view_unittest.cc',
'widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc',
'widget/desktop_aura/desktop_focus_rules_unittest.cc',
'widget/desktop_aura/desktop_native_widget_aura_unittest.cc',
'widget/desktop_aura/desktop_screen_x11_unittest.cc',
Expand Down
147 changes: 73 additions & 74 deletions ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,33 +80,6 @@ static base::LazyInstance<
std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky
g_live_client_map = LAZY_INSTANCE_INITIALIZER;

// 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) {
views::X11TopmostWindowFinder finder;
*mouse_window = finder.FindWindowAt(screen_point);
*dest_window = None;

if (*mouse_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 {
Expand Down Expand Up @@ -391,9 +364,9 @@ DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
copy_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorCopy)),
move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)),
weak_ptr_factory_(this) {
DCHECK(g_live_client_map.Get().find(xwindow) ==
g_live_client_map.Get().end());
g_live_client_map.Get().insert(std::make_pair(xwindow, this));
// Some tests change the DesktopDragDropClientAuraX11 associated with an
// |xwindow|.
g_live_client_map.Get()[xwindow] = this;

// Mark that we are aware of drag and drop concepts.
unsigned long xdnd_version = kMinXdndVersion;
Expand Down Expand Up @@ -536,6 +509,13 @@ void DesktopDragDropClientAuraX11::OnXdndStatus(
void DesktopDragDropClientAuraX11::OnXdndFinished(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndFinished";
unsigned long source_window = event.data.l[0];
if (source_current_window_ != source_window)
return;

// Clear |negotiated_operation_| if the drag was rejected.
if ((event.data.l[1] & 1) == 0)
negotiated_operation_ = ui::DragDropTypes::DRAG_NONE;

// Clear |source_current_window_| to avoid sending XdndLeave upon ending the
// move loop.
Expand Down Expand Up @@ -731,16 +711,76 @@ void DesktopDragDropClientAuraX11::OnMoveLoopEnded() {
end_move_loop_timer_.Stop();
}

XID DesktopDragDropClientAuraX11::FindWindowFor(
const gfx::Point& screen_point) {
views::X11TopmostWindowFinder finder;
::Window target = finder.FindWindowAt(screen_point);

if (target == None)
return None;

// Figure out which window we should test as XdndAware. If |target| has
// XdndProxy, it will set that proxy on target, and if not, |target|'s
// original value will remain.
ui::GetXIDProperty(target, "XdndProxy", &target);

int version;
if (ui::GetIntProperty(target, "XdndAware", &version) &&
version >= kMinXdndVersion) {
return target;
}
return None;
}

void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid,
XEvent* xev) {
DCHECK_EQ(ClientMessage, xev->type);

// 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.
//
// I'm unsure if I have to jump through those hoops, or if XSendEvent is
// sufficient.
XSendEvent(xdisplay_, xid, False, 0, xev);
}

void DesktopDragDropClientAuraX11::ProcessMouseMove(
const gfx::Point& screen_point,
unsigned long event_time) {
if (source_state_ != SOURCE_STATE_OTHER)
return;

// Find the current window the cursor is over.
::Window mouse_window = None;
::Window dest_window = None;
FindWindowFor(screen_point, &mouse_window, &dest_window);
::Window dest_window = FindWindowFor(screen_point);

if (source_current_window_ != dest_window) {
if (source_current_window_ != None)
Expand Down Expand Up @@ -988,45 +1028,4 @@ void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) {
SendXClientEvent(dest_window, &xev);
}

void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid,
XEvent* xev) {
DCHECK_EQ(ClientMessage, xev->type);

// 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.
//
// I'm unsure if I have to jump through those hoops, or if XSendEvent is
// sufficient.
XSendEvent(xdisplay_, xid, False, 0, xev);
}

} // namespace views
15 changes: 11 additions & 4 deletions ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
virtual void OnMouseReleased() OVERRIDE;
virtual void OnMoveLoopEnded() OVERRIDE;

protected:
// The following methods are virtual for the sake of testing.

// Finds the topmost X11 window at |screen_point| and returns it if it is
// Xdnd aware. Returns NULL otherwise.
virtual ::Window FindWindowFor(const gfx::Point& screen_point);

// Sends |xev| to |xid|, optionally short circuiting the round trip to the X
// server.
virtual void SendXClientEvent(::Window xid, XEvent* xev);

private:
enum SourceState {
// |source_current_window_| will receive a drop once we receive an
Expand Down Expand Up @@ -166,10 +177,6 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
unsigned long event_time);
void SendXdndDrop(::Window dest_window);

// Sends |xev| to |xid|, optionally short circuiting the round trip to the X
// server.
void SendXClientEvent(::Window xid, XEvent* xev);

// A nested message loop that notifies this object of events through the
// X11WholeScreenMoveLoopDelegate interface.
X11WholeScreenMoveLoop move_loop_;
Expand Down
Loading

0 comments on commit 172e9f1

Please sign in to comment.