blob: 6931bd5186338255f1c7d5476861b79c7a822f4f [file] [log] [blame]
// 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/views/widget/desktop_aura/desktop_drop_target_win.h"
#include "base/metrics/histogram.h"
#include "base/win/win_util.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#include "ui/events/event_constants.h"
#include "ui/wm/public/drag_drop_client.h"
#include "ui/wm/public/drag_drop_delegate.h"
using aura::client::DragDropClient;
using aura::client::DragDropDelegate;
using ui::OSExchangeData;
using ui::OSExchangeDataProviderWin;
namespace {
int ConvertKeyStateToAuraEventFlags(DWORD key_state)
{
int flags = 0;
if (key_state & MK_CONTROL)
flags |= ui::EF_CONTROL_DOWN;
if (key_state & MK_ALT)
flags |= ui::EF_ALT_DOWN;
if (key_state & MK_SHIFT)
flags |= ui::EF_SHIFT_DOWN;
if (key_state & MK_LBUTTON)
flags |= ui::EF_LEFT_MOUSE_BUTTON;
if (key_state & MK_MBUTTON)
flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
if (key_state & MK_RBUTTON)
flags |= ui::EF_RIGHT_MOUSE_BUTTON;
return flags;
}
} // namespace
namespace views {
DesktopDropTargetWin::DesktopDropTargetWin(aura::Window* root_window,
HWND window)
: ui::DropTargetWin(window),
root_window_(root_window),
target_window_(NULL) {
}
DesktopDropTargetWin::~DesktopDropTargetWin() {
if (target_window_)
target_window_->RemoveObserver(this);
}
DWORD DesktopDropTargetWin::OnDragEnter(IDataObject* data_object,
DWORD key_state,
POINT position,
DWORD effect) {
scoped_ptr<OSExchangeData> data;
scoped_ptr<ui::DropTargetEvent> event;
DragDropDelegate* delegate;
// Translate will call OnDragEntered.
Translate(data_object, key_state, position, effect, &data, &event, &delegate);
return ui::DragDropTypes::DragOperationToDropEffect(
ui::DragDropTypes::DRAG_NONE);
}
DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object,
DWORD key_state,
POINT position,
DWORD effect) {
int drag_operation = ui::DragDropTypes::DRAG_NONE;
scoped_ptr<OSExchangeData> data;
scoped_ptr<ui::DropTargetEvent> event;
DragDropDelegate* delegate;
Translate(data_object, key_state, position, effect, &data, &event, &delegate);
if (delegate)
drag_operation = delegate->OnDragUpdated(*event);
return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
}
void DesktopDropTargetWin::OnDragLeave(IDataObject* data_object) {
NotifyDragLeave();
}
DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
DWORD key_state,
POINT position,
DWORD effect) {
int drag_operation = ui::DragDropTypes::DRAG_NONE;
scoped_ptr<OSExchangeData> data;
scoped_ptr<ui::DropTargetEvent> event;
DragDropDelegate* delegate;
Translate(data_object, key_state, position, effect, &data, &event, &delegate);
if (delegate) {
drag_operation = delegate->OnPerformDrop(*event);
DragDropClient* client = aura::client::GetDragDropClient(root_window_);
if (client && !client->IsDragDropInProgress() &&
drag_operation != ui::DragDropTypes::DRAG_NONE) {
UMA_HISTOGRAM_COUNTS("Event.DragDrop.ExternalOriginDrop", 1);
}
}
if (target_window_) {
target_window_->RemoveObserver(this);
target_window_ = NULL;
}
return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
}
void DesktopDropTargetWin::OnWindowDestroyed(aura::Window* window) {
DCHECK(window == target_window_);
target_window_ = NULL;
}
void DesktopDropTargetWin::Translate(
IDataObject* data_object,
DWORD key_state,
POINT position,
DWORD effect,
scoped_ptr<OSExchangeData>* data,
scoped_ptr<ui::DropTargetEvent>* event,
DragDropDelegate** delegate) {
gfx::Point location(position.x, position.y);
gfx::Point root_location = 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 OSExchangeDataProviderWin(data_object)));
location = root_location;
aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
event->reset(new ui::DropTargetEvent(
*(data->get()),
location,
root_location,
ui::DragDropTypes::DropEffectToDragOperation(effect)));
(*event)->set_flags(ConvertKeyStateToAuraEventFlags(key_state));
if (target_window_changed)
(*delegate)->OnDragEntered(*event->get());
}
void DesktopDropTargetWin::NotifyDragLeave() {
if (!target_window_)
return;
DragDropDelegate* delegate =
aura::client::GetDragDropDelegate(target_window_);
if (delegate)
delegate->OnDragExited();
target_window_->RemoveObserver(this);
target_window_ = NULL;
}
} // namespace views