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