1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/views/widget/desktop_aura/desktop_drop_target_win.h"
6
7#include "base/win/win_util.h"
8#include "ui/aura/window.h"
9#include "ui/aura/window_tree_host.h"
10#include "ui/base/dragdrop/drag_drop_types.h"
11#include "ui/base/dragdrop/drop_target_event.h"
12#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
13#include "ui/events/event_constants.h"
14#include "ui/wm/public/drag_drop_client.h"
15#include "ui/wm/public/drag_drop_delegate.h"
16
17using aura::client::DragDropDelegate;
18using ui::OSExchangeData;
19using ui::OSExchangeDataProviderWin;
20
21namespace views {
22
23DesktopDropTargetWin::DesktopDropTargetWin(aura::Window* root_window,
24                                           HWND window)
25    : ui::DropTargetWin(window),
26      root_window_(root_window),
27      target_window_(NULL) {
28}
29
30DesktopDropTargetWin::~DesktopDropTargetWin() {
31  if (target_window_)
32    target_window_->RemoveObserver(this);
33}
34
35DWORD DesktopDropTargetWin::OnDragEnter(IDataObject* data_object,
36                                        DWORD key_state,
37                                        POINT position,
38                                        DWORD effect) {
39  scoped_ptr<OSExchangeData> data;
40  scoped_ptr<ui::DropTargetEvent> event;
41  DragDropDelegate* delegate;
42  // Translate will call OnDragEntered.
43  Translate(data_object, key_state, position, effect, &data, &event, &delegate);
44  return ui::DragDropTypes::DragOperationToDropEffect(
45      ui::DragDropTypes::DRAG_NONE);
46}
47
48DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object,
49                                       DWORD key_state,
50                                       POINT position,
51                                       DWORD effect) {
52  int drag_operation = ui::DragDropTypes::DRAG_NONE;
53  scoped_ptr<OSExchangeData> data;
54  scoped_ptr<ui::DropTargetEvent> event;
55  DragDropDelegate* delegate;
56  Translate(data_object, key_state, position, effect, &data, &event, &delegate);
57  if (delegate)
58    drag_operation = delegate->OnDragUpdated(*event);
59  return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
60}
61
62void DesktopDropTargetWin::OnDragLeave(IDataObject* data_object) {
63  NotifyDragLeave();
64}
65
66DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
67                                   DWORD key_state,
68                                   POINT position,
69                                   DWORD effect) {
70  int drag_operation = ui::DragDropTypes::DRAG_NONE;
71  scoped_ptr<OSExchangeData> data;
72  scoped_ptr<ui::DropTargetEvent> event;
73  DragDropDelegate* delegate;
74  Translate(data_object, key_state, position, effect, &data, &event, &delegate);
75  if (delegate)
76    drag_operation = delegate->OnPerformDrop(*event);
77  if (target_window_) {
78    target_window_->RemoveObserver(this);
79    target_window_ = NULL;
80  }
81  return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
82}
83
84void DesktopDropTargetWin::OnWindowDestroyed(aura::Window* window) {
85  DCHECK(window == target_window_);
86  target_window_ = NULL;
87}
88
89void DesktopDropTargetWin::Translate(
90    IDataObject* data_object,
91    DWORD key_state,
92    POINT position,
93    DWORD effect,
94    scoped_ptr<OSExchangeData>* data,
95    scoped_ptr<ui::DropTargetEvent>* event,
96    DragDropDelegate** delegate) {
97  gfx::Point location(position.x, position.y);
98  gfx::Point root_location = location;
99  root_window_->GetHost()->ConvertPointFromNativeScreen(
100      &root_location);
101  aura::Window* target_window =
102      root_window_->GetEventHandlerForPoint(root_location);
103  bool target_window_changed = false;
104  if (target_window != target_window_) {
105    if (target_window_)
106      NotifyDragLeave();
107    target_window_ = target_window;
108    if (target_window_)
109      target_window_->AddObserver(this);
110    target_window_changed = true;
111  }
112  *delegate = NULL;
113  if (!target_window_)
114    return;
115  *delegate = aura::client::GetDragDropDelegate(target_window_);
116  if (!*delegate)
117    return;
118
119  data->reset(new OSExchangeData(new OSExchangeDataProviderWin(data_object)));
120  location = root_location;
121  aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
122  event->reset(new ui::DropTargetEvent(
123      *(data->get()),
124      location,
125      root_location,
126      ui::DragDropTypes::DropEffectToDragOperation(effect)));
127  int flags = 0;
128  flags |= base::win::IsAltPressed() ? ui::EF_ALT_DOWN : ui::EF_NONE;
129  flags |= base::win::IsShiftPressed() ? ui::EF_SHIFT_DOWN : ui::EF_NONE;
130  flags |= base::win::IsCtrlPressed() ? ui::EF_CONTROL_DOWN : ui::EF_NONE;
131  (*event)->set_flags(flags);
132  if (target_window_changed)
133    (*delegate)->OnDragEntered(*event->get());
134}
135
136void DesktopDropTargetWin::NotifyDragLeave() {
137  if (!target_window_)
138    return;
139  DragDropDelegate* delegate =
140      aura::client::GetDragDropDelegate(target_window_);
141  if (delegate)
142    delegate->OnDragExited();
143  target_window_->RemoveObserver(this);
144  target_window_ = NULL;
145}
146
147}  // namespace views
148