This source file includes following definitions.
- screen_loc_
- window
- ShouldStopIterating
- FindWindowFor
- fetched_targets
- suggested_action_
- OnStartXdndPositionMessage
- RequestNextTarget
- OnSelectionNotify
- ReadActions
- GetDragOperation
- MaskOpeartion
- Dispatch
- weak_ptr_factory_
- GetForWindow
- OnXdndEnter
- OnXdndLeave
- OnXdndPosition
- OnXdndStatus
- OnXdndFinished
- OnXdndDrop
- OnSelectionNotify
- StartDragAndDrop
- DragUpdate
- DragCancel
- IsDragDropInProgress
- OnWindowDestroyed
- OnMouseMovement
- OnMouseReleased
- OnMoveLoopEnded
- StartEndMoveLoopTimer
- EndMoveLoop
- DragTranslate
- NotifyDragLeave
- DragOperationToAtom
- AtomToDragOperation
- GetOfferedDragOperations
- GetFormatMap
- CompleteXdndPosition
- SendXdndEnter
- SendXdndLeave
- SendXdndPosition
- SendXdndDrop
- SendXClientEvent
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
#include <X11/Xatom.h>
#include "base/event_types.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_pump_dispatcher.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/wm/public/drag_drop_client.h"
#include "ui/wm/public/drag_drop_delegate.h"
using aura::client::DragDropDelegate;
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 kXdndActionDirectSave[] = "XdndActionDirectSave";
const char kChromiumDragReciever[] = "_CHROMIUM_DRAG_RECEIVER";
const char kXdndSelection[] = "XdndSelection";
const char kXdndDirectSave0[] = "XdndDirectSave0";
const char* kAtomsToCache[] = {
kChromiumDragReciever,
"XdndActionAsk",
kXdndActionCopy,
kXdndActionDirectSave,
kXdndActionLink,
"XdndActionList",
kXdndActionMove,
"XdndActionPrivate",
"XdndAware",
kXdndDirectSave0,
"XdndDrop",
"XdndEnter",
"XdndFinished",
"XdndLeave",
"XdndPosition",
"XdndProxy",
kXdndSelection,
"XdndStatus",
"XdndTypeList",
ui::Clipboard::kMimeTypeText,
"_NET_WM_WINDOW_TYPE_MENU",
NULL
};
const int kEndMoveLoopTimeoutMs = 30000;
static base::LazyInstance<
std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky
g_live_client_map = LAZY_INSTANCE_INITIALIZER;
class DragTargetWindowFinder : public ui::EnumerateWindowsDelegate {
public:
DragTargetWindowFinder(XID ignored_icon_window,
Atom menu_type_atom,
gfx::Point screen_loc)
: ignored_icon_window_(ignored_icon_window),
output_window_(None),
menu_type_atom_(menu_type_atom),
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;
int value = 0;
if (ui::PropertyExists(window, "WM_STATE") ||
(ui::GetIntProperty(window, "_NET_WM_WINDOW_TYPE", &value) &&
static_cast<Atom>(value) == menu_type_atom_)) {
output_window_ = window;
return true;
}
return false;
}
private:
XID ignored_icon_window_;
XID output_window_;
const Atom menu_type_atom_;
gfx::Point screen_loc_;
DISALLOW_COPY_AND_ASSIGN(DragTargetWindowFinder);
};
void FindWindowFor(const gfx::Point& screen_point,
::Window* mouse_window, ::Window* dest_window,
Atom menu_type_atom) {
DragTargetWindowFinder finder(None, menu_type_atom, screen_point);
*mouse_window = finder.window();
*dest_window = None;
if (finder.window() == None)
return;
XID target = *mouse_window;
ui::GetXIDProperty(*mouse_window, "XdndProxy", &target);
int version;
if (ui::GetIntProperty(target, "XdndAware", &version) &&
version >= kMinXdndVersion) {
*dest_window = target;
}
}
}
namespace views {
DesktopDragDropClientAuraX11*
DesktopDragDropClientAuraX11::g_current_drag_drop_client = NULL;
class DesktopDragDropClientAuraX11::X11DragContext :
public base::MessagePumpDispatcher {
public:
X11DragContext(ui::X11AtomCache* atom_cache,
::Window local_window,
const XClientMessageEvent& event);
virtual ~X11DragContext();
void OnStartXdndPositionMessage(DesktopDragDropClientAuraX11* client,
::Atom suggested_action,
::Window source_window,
const gfx::Point& screen_point);
void RequestNextTarget();
void OnSelectionNotify(const XSelectionEvent& xselection);
const ui::SelectionFormatMap& fetched_targets() { return fetched_targets_; }
void ReadActions();
int GetDragOperation() const;
private:
void MaskOpeartion(::Atom xdnd_operation, int* drag_operation) const;
virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE;
ui::X11AtomCache* atom_cache_;
::Window local_window_;
unsigned long source_window_;
DesktopDragDropClientAuraX11* drag_drop_client_;
bool waiting_to_handle_position_;
gfx::Point screen_point_;
ui::SelectionFormatMap fetched_targets_;
std::vector<Atom> unfetched_targets_;
Atom suggested_action_;
std::vector<Atom> actions_;
DISALLOW_COPY_AND_ASSIGN(X11DragContext);
};
DesktopDragDropClientAuraX11::X11DragContext::X11DragContext(
ui::X11AtomCache* atom_cache,
::Window local_window,
const XClientMessageEvent& event)
: atom_cache_(atom_cache),
local_window_(local_window),
source_window_(event.data.l[0]),
drag_drop_client_(NULL),
waiting_to_handle_position_(false),
suggested_action_(None) {
bool get_types = ((event.data.l[1] & 1) != 0);
if (get_types) {
if (!ui::GetAtomArrayProperty(source_window_,
"XdndTypeList",
&unfetched_targets_)) {
return;
}
} else {
for (int i = 0; i < 3; ++i) {
if (event.data.l[2+i] != None) {
unfetched_targets_.push_back(event.data.l[2+i]);
}
}
}
DesktopDragDropClientAuraX11* client =
DesktopDragDropClientAuraX11::GetForWindow(source_window_);
if (!client) {
base::MessagePumpX11::Current()->AddDispatcherForWindow(
this, source_window_);
XSelectInput(gfx::GetXDisplay(), source_window_, PropertyChangeMask);
XSync(gfx::GetXDisplay(), False);
} else {
fetched_targets_ = client->GetFormatMap();
unfetched_targets_.clear();
}
ReadActions();
}
DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() {
DesktopDragDropClientAuraX11* client =
DesktopDragDropClientAuraX11::GetForWindow(source_window_);
if (!client) {
base::MessagePumpX11::Current()->RemoveDispatcherForWindow(
source_window_);
}
}
void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage(
DesktopDragDropClientAuraX11* client,
::Atom suggested_action,
::Window source_window,
const gfx::Point& screen_point) {
DCHECK_EQ(source_window_, source_window);
suggested_action_ = suggested_action;
if (!unfetched_targets_.empty()) {
screen_point_ = screen_point;
drag_drop_client_ = client;
waiting_to_handle_position_ = true;
fetched_targets_ = ui::SelectionFormatMap();
RequestNextTarget();
} else {
client->CompleteXdndPosition(source_window, screen_point);
}
}
void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() {
::Atom target = unfetched_targets_.back();
unfetched_targets_.pop_back();
XConvertSelection(gfx::GetXDisplay(),
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));
scoped_refptr<base::RefCountedMemory> data;
::Atom type = None;
if (ui::GetRawBytesOfProperty(local_window_, event.property,
&data, NULL, NULL, &type)) {
fetched_targets_.Insert(event.target, data);
}
if (!unfetched_targets_.empty()) {
RequestNextTarget();
} else {
waiting_to_handle_position_ = false;
drag_drop_client_->CompleteXdndPosition(source_window_, screen_point_);
drag_drop_client_ = NULL;
}
}
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_ = client->GetOfferedDragOperations();
}
}
int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const {
int drag_operation = ui::DragDropTypes::DRAG_NONE;
for (std::vector<Atom>::const_iterator it = actions_.begin();
it != actions_.end(); ++it) {
MaskOpeartion(*it, &drag_operation);
}
MaskOpeartion(suggested_action_, &drag_operation);
return drag_operation;
}
void DesktopDragDropClientAuraX11::X11DragContext::MaskOpeartion(
::Atom xdnd_operation,
int* drag_operation) const {
if (xdnd_operation == atom_cache_->GetAtom(kXdndActionCopy))
*drag_operation |= ui::DragDropTypes::DRAG_COPY;
else if (xdnd_operation == atom_cache_->GetAtom(kXdndActionMove))
*drag_operation |= ui::DragDropTypes::DRAG_MOVE;
else if (xdnd_operation == atom_cache_->GetAtom(kXdndActionLink))
*drag_operation |= ui::DragDropTypes::DRAG_LINK;
}
uint32_t DesktopDragDropClientAuraX11::X11DragContext::Dispatch(
const base::NativeEvent& event) {
if (event->type == PropertyNotify &&
event->xproperty.atom == atom_cache_->GetAtom("XdndActionList")) {
ReadActions();
}
return POST_DISPATCH_NONE;
}
DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
aura::Window* root_window,
views::DesktopNativeCursorManager* cursor_manager,
Display* xdisplay,
::Window xwindow)
: move_loop_(this),
root_window_(root_window),
xdisplay_(xdisplay),
xwindow_(xwindow),
atom_cache_(xdisplay_, kAtomsToCache),
target_window_(NULL),
source_provider_(NULL),
source_current_window_(None),
source_state_(SOURCE_STATE_OTHER),
drag_operation_(0),
resulting_operation_(0),
grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorGrabbing)),
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));
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.Get().erase(xwindow_);
NotifyDragLeave();
}
DesktopDragDropClientAuraX11* DesktopDragDropClientAuraX11::GetForWindow(
::Window window) {
std::map< ::Window, DesktopDragDropClientAuraX11*>::const_iterator it =
g_live_client_map.Get().find(window);
if (it == g_live_client_map.Get().end())
return NULL;
return it->second;
}
void DesktopDragDropClientAuraX11::OnXdndEnter(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndEnter";
int version = (event.data.l[1] & 0xff000000) >> 24;
if (version < 3) {
LOG(ERROR) << "Received old XdndEnter message.";
return;
}
target_current_context_.reset();
target_current_context_.reset(
new X11DragContext(&atom_cache_, xwindow_, event));
}
void DesktopDragDropClientAuraX11::OnXdndLeave(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndLeave";
NotifyDragLeave();
target_current_context_.reset();
}
void DesktopDragDropClientAuraX11::OnXdndPosition(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndPosition";
unsigned long source_window = event.data.l[0];
int x_root_window = event.data.l[2] >> 16;
int y_root_window = event.data.l[2] & 0xffff;
::Atom suggested_action = event.data.l[4];
if (!target_current_context_.get()) {
NOTREACHED();
return;
}
target_current_context_->OnStartXdndPositionMessage(
this, suggested_action, 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];
waiting_on_status_.erase(source_window);
if (source_window != source_current_window_)
return;
int drag_operation = ui::DragDropTypes::DRAG_NONE;
if (event.data.l[1] & 1) {
::Atom atom_operation = event.data.l[4];
negotiated_operation_[source_window] = atom_operation;
drag_operation = AtomToDragOperation(atom_operation);
}
switch (drag_operation) {
case ui::DragDropTypes::DRAG_COPY:
move_loop_.UpdateCursor(copy_grab_cursor_);
break;
case ui::DragDropTypes::DRAG_MOVE:
move_loop_.UpdateCursor(move_grab_cursor_);
break;
default:
move_loop_.UpdateCursor(grab_cursor_);
break;
}
if (source_state_ == SOURCE_STATE_PENDING_DROP) {
source_state_ = SOURCE_STATE_DROPPED;
SendXdndDrop(source_window);
return;
}
NextPositionMap::iterator it = next_position_message_.find(source_window);
if (source_state_ == SOURCE_STATE_OTHER &&
it != next_position_message_.end()) {
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(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndDrop";
unsigned long source_window = event.data.l[0];
int drag_operation = ui::DragDropTypes::DRAG_NONE;
if (target_window_) {
aura::client::DragDropDelegate* delegate =
aura::client::GetDragDropDelegate(target_window_);
if (delegate) {
ui::OSExchangeData data(new ui::OSExchangeDataProviderAuraX11(
xwindow_, target_current_context_->fetched_targets()));
ui::DropTargetEvent event(data,
target_window_location_,
target_window_root_location_,
target_current_context_->GetDragOperation());
drag_operation = delegate->OnPerformDrop(event);
}
target_window_->RemoveObserver(this);
target_window_ = NULL;
}
XEvent xev;
xev.xclient.type = ClientMessage;
xev.xclient.message_type = atom_cache_.GetAtom("XdndFinished");
xev.xclient.format = 32;
xev.xclient.window = source_window;
xev.xclient.data.l[0] = xwindow_;
xev.xclient.data.l[1] = (drag_operation != 0) ? 1 : 0;
xev.xclient.data.l[2] = DragOperationToAtom(drag_operation);
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::Window* root_window,
aura::Window* source_window,
const gfx::Point& root_location,
int operation,
ui::DragDropTypes::DragEventSource source) {
source_current_window_ = None;
DCHECK(!g_current_drag_drop_client);
g_current_drag_drop_client = this;
waiting_on_status_.clear();
source_state_ = SOURCE_STATE_OTHER;
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();
if (!source_provider_->file_contents_name().empty()) {
actions.push_back(atom_cache_.GetAtom(kXdndActionDirectSave));
ui::SetStringProperty(
xwindow_,
atom_cache_.GetAtom(kXdndDirectSave0),
atom_cache_.GetAtom(ui::Clipboard::kMimeTypeText),
source_provider_->file_contents_name().AsUTF8Unsafe());
}
ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions);
base::WeakPtr<DesktopDragDropClientAuraX11> alive(
weak_ptr_factory_.GetWeakPtr());
move_loop_.SetDragImage(source_provider_->GetDragImage(),
source_provider_->GetDragImageOffset());
move_loop_.RunMoveLoop(source_window, grab_cursor_);
if (alive) {
move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF());
source_provider_ = NULL;
g_current_drag_drop_client = NULL;
drag_operation_ = 0;
XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList"));
XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0));
return resulting_operation_;
}
return ui::DragDropTypes::DRAG_NONE;
}
void DesktopDragDropClientAuraX11::DragUpdate(aura::Window* target,
const ui::LocatedEvent& event) {
NOTIMPLEMENTED();
}
void DesktopDragDropClientAuraX11::Drop(aura::Window* target,
const ui::LocatedEvent& event) {
NOTIMPLEMENTED();
}
void DesktopDragDropClientAuraX11::DragCancel() {
move_loop_.EndMoveLoop();
}
bool DesktopDragDropClientAuraX11::IsDragDropInProgress() {
return !!g_current_drag_drop_client;
}
void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) {
DCHECK_EQ(target_window_, window);
target_window_ = NULL;
}
void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) {
gfx::Point screen_point(event->x_root, event->y_root);
if (source_state_ != SOURCE_STATE_OTHER)
return;
::Window mouse_window = None;
::Window dest_window = None;
FindWindowFor(screen_point, &mouse_window, &dest_window,
atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU"));
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_)) {
source_state_ = SOURCE_STATE_PENDING_DROP;
StartEndMoveLoopTimer();
return;
}
std::map< ::Window, ::Atom>::iterator it =
negotiated_operation_.find(source_current_window_);
if (it != negotiated_operation_.end() && it->second != None) {
source_state_ = SOURCE_STATE_DROPPED;
SendXdndDrop(source_current_window_);
StartEndMoveLoopTimer();
return;
}
SendXdndLeave(source_current_window_);
source_current_window_ = None;
}
move_loop_.EndMoveLoop();
}
void DesktopDragDropClientAuraX11::OnMoveLoopEnded() {
if (source_current_window_ != None)
SendXdndLeave(source_current_window_);
target_current_context_.reset();
source_state_ = SOURCE_STATE_OTHER;
end_move_loop_timer_.Stop();
}
void DesktopDragDropClientAuraX11::StartEndMoveLoopTimer() {
end_move_loop_timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(
kEndMoveLoopTimeoutMs),
this,
&DesktopDragDropClientAuraX11::EndMoveLoop);
}
void DesktopDragDropClientAuraX11::EndMoveLoop() {
move_loop_.EndMoveLoop();
}
void DesktopDragDropClientAuraX11::DragTranslate(
const gfx::Point& root_window_location,
scoped_ptr<ui::OSExchangeData>* data,
scoped_ptr<ui::DropTargetEvent>* event,
aura::client::DragDropDelegate** delegate) {
gfx::Point root_location = root_window_location;
root_window_->GetHost()->ConvertPointFromNativeScreen(&root_location);
aura::Window* target_window =
root_window_->GetEventHandlerForPoint(root_location);
bool target_window_changed = false;
if (target_window != target_window_) {
if (target_window_)
NotifyDragLeave();
target_window_ = target_window;
if (target_window_)
target_window_->AddObserver(this);
target_window_changed = true;
}
*delegate = NULL;
if (!target_window_)
return;
*delegate = aura::client::GetDragDropDelegate(target_window_);
if (!*delegate)
return;
data->reset(new OSExchangeData(new ui::OSExchangeDataProviderAuraX11(
xwindow_, target_current_context_->fetched_targets())));
gfx::Point location = root_location;
aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
target_window_location_ = location;
target_window_root_location_ = root_location;
event->reset(new ui::DropTargetEvent(
*(data->get()),
location,
root_location,
target_current_context_->GetDragOperation()));
if (target_window_changed)
(*delegate)->OnDragEntered(*event->get());
}
void DesktopDragDropClientAuraX11::NotifyDragLeave() {
if (!target_window_)
return;
DragDropDelegate* delegate =
aura::client::GetDragDropDelegate(target_window_);
if (delegate)
delegate->OnDragExited();
target_window_->RemoveObserver(this);
target_window_ = NULL;
}
::Atom DesktopDragDropClientAuraX11::DragOperationToAtom(
int drag_operation) {
if (drag_operation & ui::DragDropTypes::DRAG_COPY)
return atom_cache_.GetAtom(kXdndActionCopy);
if (drag_operation & ui::DragDropTypes::DRAG_MOVE)
return atom_cache_.GetAtom(kXdndActionMove);
if (drag_operation & ui::DragDropTypes::DRAG_LINK)
return atom_cache_.GetAtom(kXdndActionLink);
return None;
}
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;
}
ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const {
return source_provider_ ? source_provider_->GetFormatMap() :
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);
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);
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 {
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) {
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);
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;
}
}
XSendEvent(xdisplay_, xid, False, 0, xev);
}
}