// 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 data; scoped_ptr 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 data; scoped_ptr 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 data; scoped_ptr 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* data, scoped_ptr* 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