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 <utility>
8 
9 #include "base/win/win_util.h"
10 #include "ui/aura/client/drag_drop_client.h"
11 #include "ui/aura/client/drag_drop_delegate.h"
12 #include "ui/aura/window.h"
13 #include "ui/aura/window_tree_host.h"
14 #include "ui/base/dragdrop/drag_drop_types.h"
15 #include "ui/base/dragdrop/drop_target_event.h"
16 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
17 #include "ui/events/event_constants.h"
18 
19 using aura::client::DragDropClient;
20 using aura::client::DragDropDelegate;
21 using ui::OSExchangeData;
22 using ui::OSExchangeDataProviderWin;
23 
24 namespace {
25 
ConvertKeyStateToAuraEventFlags(DWORD key_state)26 int ConvertKeyStateToAuraEventFlags(DWORD key_state) {
27   int flags = 0;
28 
29   if (key_state & MK_CONTROL)
30     flags |= ui::EF_CONTROL_DOWN;
31   if (key_state & MK_ALT)
32     flags |= ui::EF_ALT_DOWN;
33   if (key_state & MK_SHIFT)
34     flags |= ui::EF_SHIFT_DOWN;
35   if (key_state & MK_LBUTTON)
36     flags |= ui::EF_LEFT_MOUSE_BUTTON;
37   if (key_state & MK_MBUTTON)
38     flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
39   if (key_state & MK_RBUTTON)
40     flags |= ui::EF_RIGHT_MOUSE_BUTTON;
41 
42   return flags;
43 }
44 
45 }  // namespace
46 
47 namespace views {
48 
DesktopDropTargetWin(aura::Window * root_window)49 DesktopDropTargetWin::DesktopDropTargetWin(aura::Window* root_window)
50     : root_window_(root_window), target_window_(nullptr) {}
51 
~DesktopDropTargetWin()52 DesktopDropTargetWin::~DesktopDropTargetWin() {
53   if (target_window_)
54     target_window_->RemoveObserver(this);
55 }
56 
OnDragEnter(IDataObject * data_object,DWORD key_state,POINT position,DWORD effect)57 DWORD DesktopDropTargetWin::OnDragEnter(IDataObject* data_object,
58                                         DWORD key_state,
59                                         POINT position,
60                                         DWORD effect) {
61   std::unique_ptr<OSExchangeData> data;
62   std::unique_ptr<ui::DropTargetEvent> event;
63   DragDropDelegate* delegate;
64   // Translate will call OnDragEntered.
65   Translate(data_object, key_state, position, effect, &data, &event, &delegate);
66   return ui::DragDropTypes::DragOperationToDropEffect(
67       ui::DragDropTypes::DRAG_NONE);
68 }
69 
OnDragOver(IDataObject * data_object,DWORD key_state,POINT position,DWORD effect)70 DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object,
71                                        DWORD key_state,
72                                        POINT position,
73                                        DWORD effect) {
74   int drag_operation = ui::DragDropTypes::DRAG_NONE;
75   std::unique_ptr<OSExchangeData> data;
76   std::unique_ptr<ui::DropTargetEvent> event;
77   DragDropDelegate* delegate;
78   Translate(data_object, key_state, position, effect, &data, &event, &delegate);
79   if (delegate)
80     drag_operation = delegate->OnDragUpdated(*event);
81 
82   return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
83 }
84 
OnDragLeave(IDataObject * data_object)85 void DesktopDropTargetWin::OnDragLeave(IDataObject* data_object) {
86   NotifyDragLeave();
87 }
88 
OnDrop(IDataObject * data_object,DWORD key_state,POINT position,DWORD effect)89 DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
90                                    DWORD key_state,
91                                    POINT position,
92                                    DWORD effect) {
93   int drag_operation = ui::DragDropTypes::DRAG_NONE;
94   std::unique_ptr<OSExchangeData> data;
95   std::unique_ptr<ui::DropTargetEvent> event;
96   DragDropDelegate* delegate;
97   Translate(data_object, key_state, position, effect, &data, &event, &delegate);
98   if (delegate)
99     drag_operation = delegate->OnPerformDrop(*event, std::move(data));
100   if (target_window_) {
101     target_window_->RemoveObserver(this);
102     target_window_ = nullptr;
103   }
104   return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
105 }
106 
OnWindowDestroyed(aura::Window * window)107 void DesktopDropTargetWin::OnWindowDestroyed(aura::Window* window) {
108   DCHECK(window == target_window_);
109   target_window_ = nullptr;
110 }
111 
Translate(IDataObject * data_object,DWORD key_state,POINT position,DWORD effect,std::unique_ptr<OSExchangeData> * data,std::unique_ptr<ui::DropTargetEvent> * event,DragDropDelegate ** delegate)112 void DesktopDropTargetWin::Translate(
113     IDataObject* data_object,
114     DWORD key_state,
115     POINT position,
116     DWORD effect,
117     std::unique_ptr<OSExchangeData>* data,
118     std::unique_ptr<ui::DropTargetEvent>* event,
119     DragDropDelegate** delegate) {
120   gfx::Point location(position.x, position.y);
121   gfx::Point root_location = location;
122   root_window_->GetHost()->ConvertScreenInPixelsToDIP(&root_location);
123   aura::Window* target_window =
124       root_window_->GetEventHandlerForPoint(root_location);
125   bool target_window_changed = false;
126   if (target_window != target_window_) {
127     if (target_window_)
128       NotifyDragLeave();
129     target_window_ = target_window;
130     if (target_window_)
131       target_window_->AddObserver(this);
132     target_window_changed = true;
133   }
134   *delegate = nullptr;
135   if (!target_window_)
136     return;
137   *delegate = aura::client::GetDragDropDelegate(target_window_);
138   if (!*delegate)
139     return;
140 
141   *data = std::make_unique<OSExchangeData>(
142       std::make_unique<OSExchangeDataProviderWin>(data_object));
143   location = root_location;
144   aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
145   *event = std::make_unique<ui::DropTargetEvent>(
146       *(data->get()), gfx::PointF(location), gfx::PointF(root_location),
147       ui::DragDropTypes::DropEffectToDragOperation(effect));
148   (*event)->set_flags(ConvertKeyStateToAuraEventFlags(key_state));
149   if (target_window_changed)
150     (*delegate)->OnDragEntered(*event->get());
151 }
152 
NotifyDragLeave()153 void DesktopDropTargetWin::NotifyDragLeave() {
154   if (!target_window_)
155     return;
156   DragDropDelegate* delegate =
157       aura::client::GetDragDropDelegate(target_window_);
158   if (delegate)
159     delegate->OnDragExited();
160   target_window_->RemoveObserver(this);
161   target_window_ = nullptr;
162 }
163 
164 }  // namespace views
165