OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/tab_contents/tab_contents_drag_win.h" | 5 #include "content/browser/tab_contents/web_contents_drag_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
14 #include "base/pickle.h" | 14 #include "base/pickle.h" |
15 #include "base/threading/platform_thread.h" | 15 #include "base/threading/platform_thread.h" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 return TRUE; | 65 return TRUE; |
66 } | 66 } |
67 } | 67 } |
68 return CallNextHookEx(msg_hook, code, wparam, lparam); | 68 return CallNextHookEx(msg_hook, code, wparam, lparam); |
69 } | 69 } |
70 | 70 |
71 } // namespace | 71 } // namespace |
72 | 72 |
73 class DragDropThread : public base::Thread { | 73 class DragDropThread : public base::Thread { |
74 public: | 74 public: |
75 explicit DragDropThread(TabContentsDragWin* drag_handler) | 75 explicit DragDropThread(WebContentsDragWin* drag_handler) |
76 : base::Thread("Chrome_DragDropThread"), | 76 : base::Thread("Chrome_DragDropThread"), |
77 drag_handler_(drag_handler) { | 77 drag_handler_(drag_handler) { |
78 } | 78 } |
79 | 79 |
80 virtual ~DragDropThread() { | 80 virtual ~DragDropThread() { |
81 Thread::Stop(); | 81 Thread::Stop(); |
82 } | 82 } |
83 | 83 |
84 protected: | 84 protected: |
85 // base::Thread implementations: | 85 // base::Thread implementations: |
86 virtual void Init() { | 86 virtual void Init() { |
87 int ole_result = OleInitialize(NULL); | 87 int ole_result = OleInitialize(NULL); |
88 DCHECK(ole_result == S_OK); | 88 DCHECK(ole_result == S_OK); |
89 } | 89 } |
90 | 90 |
91 virtual void CleanUp() { | 91 virtual void CleanUp() { |
92 OleUninitialize(); | 92 OleUninitialize(); |
93 } | 93 } |
94 | 94 |
95 private: | 95 private: |
96 // Hold a reference count to TabContentsDragWin to make sure that it is always | 96 // Hold a reference count to WebContentsDragWin to make sure that it is always |
97 // alive in the thread lifetime. | 97 // alive in the thread lifetime. |
98 scoped_refptr<TabContentsDragWin> drag_handler_; | 98 scoped_refptr<WebContentsDragWin> drag_handler_; |
99 | 99 |
100 DISALLOW_COPY_AND_ASSIGN(DragDropThread); | 100 DISALLOW_COPY_AND_ASSIGN(DragDropThread); |
101 }; | 101 }; |
102 | 102 |
103 TabContentsDragWin::TabContentsDragWin( | 103 WebContentsDragWin::WebContentsDragWin( |
104 gfx::NativeWindow source_window, | 104 gfx::NativeWindow source_window, |
105 content::WebContents* web_contents, | 105 content::WebContents* web_contents, |
106 WebDragDest* drag_dest, | 106 WebDragDest* drag_dest, |
107 const base::Callback<void()>& drag_end_callback) | 107 const base::Callback<void()>& drag_end_callback) |
108 : drag_drop_thread_id_(0), | 108 : drag_drop_thread_id_(0), |
109 source_window_(source_window), | 109 source_window_(source_window), |
110 web_contents_(web_contents), | 110 web_contents_(web_contents), |
111 drag_dest_(drag_dest), | 111 drag_dest_(drag_dest), |
112 drag_ended_(false), | 112 drag_ended_(false), |
113 old_drop_target_suspended_state_(false), | 113 old_drop_target_suspended_state_(false), |
114 drag_end_callback_(drag_end_callback) { | 114 drag_end_callback_(drag_end_callback) { |
115 } | 115 } |
116 | 116 |
117 TabContentsDragWin::~TabContentsDragWin() { | 117 WebContentsDragWin::~WebContentsDragWin() { |
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
119 DCHECK(!drag_drop_thread_.get()); | 119 DCHECK(!drag_drop_thread_.get()); |
120 } | 120 } |
121 | 121 |
122 void TabContentsDragWin::StartDragging(const WebDropData& drop_data, | 122 void WebContentsDragWin::StartDragging(const WebDropData& drop_data, |
123 WebDragOperationsMask ops, | 123 WebDragOperationsMask ops, |
124 const SkBitmap& image, | 124 const SkBitmap& image, |
125 const gfx::Point& image_offset) { | 125 const gfx::Point& image_offset) { |
126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
127 | 127 |
128 drag_source_ = new WebDragSource(source_window_, web_contents_); | 128 drag_source_ = new WebDragSource(source_window_, web_contents_); |
129 | 129 |
130 const GURL& page_url = web_contents_->GetURL(); | 130 const GURL& page_url = web_contents_->GetURL(); |
131 const std::string& page_encoding = web_contents_->GetEncoding(); | 131 const std::string& page_encoding = web_contents_->GetEncoding(); |
132 | 132 |
133 // If it is not drag-out, do the drag-and-drop in the current UI thread. | 133 // If it is not drag-out, do the drag-and-drop in the current UI thread. |
134 if (drop_data.download_metadata.empty()) { | 134 if (drop_data.download_metadata.empty()) { |
135 DoDragging(drop_data, ops, page_url, page_encoding, image, image_offset); | 135 DoDragging(drop_data, ops, page_url, page_encoding, image, image_offset); |
136 EndDragging(false); | 136 EndDragging(false); |
137 return; | 137 return; |
138 } | 138 } |
139 | 139 |
140 // We do not want to drag and drop the download to itself. | 140 // We do not want to drag and drop the download to itself. |
141 old_drop_target_suspended_state_ = drag_dest_->suspended(); | 141 old_drop_target_suspended_state_ = drag_dest_->suspended(); |
142 drag_dest_->set_suspended(true); | 142 drag_dest_->set_suspended(true); |
143 | 143 |
144 // Start a background thread to do the drag-and-drop. | 144 // Start a background thread to do the drag-and-drop. |
145 DCHECK(!drag_drop_thread_.get()); | 145 DCHECK(!drag_drop_thread_.get()); |
146 drag_drop_thread_.reset(new DragDropThread(this)); | 146 drag_drop_thread_.reset(new DragDropThread(this)); |
147 base::Thread::Options options; | 147 base::Thread::Options options; |
148 options.message_loop_type = MessageLoop::TYPE_UI; | 148 options.message_loop_type = MessageLoop::TYPE_UI; |
149 if (drag_drop_thread_->StartWithOptions(options)) { | 149 if (drag_drop_thread_->StartWithOptions(options)) { |
150 drag_drop_thread_->message_loop()->PostTask( | 150 drag_drop_thread_->message_loop()->PostTask( |
151 FROM_HERE, | 151 FROM_HERE, |
152 base::Bind(&TabContentsDragWin::StartBackgroundDragging, this, | 152 base::Bind(&WebContentsDragWin::StartBackgroundDragging, this, |
153 drop_data, ops, page_url, page_encoding, image, | 153 drop_data, ops, page_url, page_encoding, image, |
154 image_offset)); | 154 image_offset)); |
155 } | 155 } |
156 | 156 |
157 // Install a hook procedure to monitor the messages so that we can forward | 157 // Install a hook procedure to monitor the messages so that we can forward |
158 // the appropriate ones to the background thread. | 158 // the appropriate ones to the background thread. |
159 drag_out_thread_id = drag_drop_thread_->thread_id(); | 159 drag_out_thread_id = drag_drop_thread_->thread_id(); |
160 mouse_up_received = false; | 160 mouse_up_received = false; |
161 DCHECK(!msg_hook); | 161 DCHECK(!msg_hook); |
162 msg_hook = SetWindowsHookEx(WH_MSGFILTER, | 162 msg_hook = SetWindowsHookEx(WH_MSGFILTER, |
163 MsgFilterProc, | 163 MsgFilterProc, |
164 NULL, | 164 NULL, |
165 GetCurrentThreadId()); | 165 GetCurrentThreadId()); |
166 | 166 |
167 // Attach the input state of the background thread to the UI thread so that | 167 // Attach the input state of the background thread to the UI thread so that |
168 // SetCursor can work from the background thread. | 168 // SetCursor can work from the background thread. |
169 AttachThreadInput(drag_out_thread_id, GetCurrentThreadId(), TRUE); | 169 AttachThreadInput(drag_out_thread_id, GetCurrentThreadId(), TRUE); |
170 } | 170 } |
171 | 171 |
172 void TabContentsDragWin::StartBackgroundDragging( | 172 void WebContentsDragWin::StartBackgroundDragging( |
173 const WebDropData& drop_data, | 173 const WebDropData& drop_data, |
174 WebDragOperationsMask ops, | 174 WebDragOperationsMask ops, |
175 const GURL& page_url, | 175 const GURL& page_url, |
176 const std::string& page_encoding, | 176 const std::string& page_encoding, |
177 const SkBitmap& image, | 177 const SkBitmap& image, |
178 const gfx::Point& image_offset) { | 178 const gfx::Point& image_offset) { |
179 drag_drop_thread_id_ = base::PlatformThread::CurrentId(); | 179 drag_drop_thread_id_ = base::PlatformThread::CurrentId(); |
180 | 180 |
181 DoDragging(drop_data, ops, page_url, page_encoding, image, image_offset); | 181 DoDragging(drop_data, ops, page_url, page_encoding, image, image_offset); |
182 BrowserThread::PostTask( | 182 BrowserThread::PostTask( |
183 BrowserThread::UI, | 183 BrowserThread::UI, |
184 FROM_HERE, | 184 FROM_HERE, |
185 base::Bind(&TabContentsDragWin::EndDragging, this, true)); | 185 base::Bind(&WebContentsDragWin::EndDragging, this, true)); |
186 } | 186 } |
187 | 187 |
188 void TabContentsDragWin::PrepareDragForDownload( | 188 void WebContentsDragWin::PrepareDragForDownload( |
189 const WebDropData& drop_data, | 189 const WebDropData& drop_data, |
190 ui::OSExchangeData* data, | 190 ui::OSExchangeData* data, |
191 const GURL& page_url, | 191 const GURL& page_url, |
192 const std::string& page_encoding) { | 192 const std::string& page_encoding) { |
193 // Parse the download metadata. | 193 // Parse the download metadata. |
194 string16 mime_type; | 194 string16 mime_type; |
195 FilePath file_name; | 195 FilePath file_name; |
196 GURL download_url; | 196 GURL download_url; |
197 if (!drag_download_util::ParseDownloadMetadata(drop_data.download_metadata, | 197 if (!drag_download_util::ParseDownloadMetadata(drop_data.download_metadata, |
198 &mime_type, | 198 &mime_type, |
(...skipping 23 matching lines...) Expand all Loading... |
222 page_encoding, | 222 page_encoding, |
223 web_contents_); | 223 web_contents_); |
224 ui::OSExchangeData::DownloadFileInfo file_download(FilePath(), | 224 ui::OSExchangeData::DownloadFileInfo file_download(FilePath(), |
225 download_file.get()); | 225 download_file.get()); |
226 data->SetDownloadFileInfo(file_download); | 226 data->SetDownloadFileInfo(file_download); |
227 | 227 |
228 // Enable asynchronous operation. | 228 // Enable asynchronous operation. |
229 ui::OSExchangeDataProviderWin::GetIAsyncOperation(*data)->SetAsyncMode(TRUE); | 229 ui::OSExchangeDataProviderWin::GetIAsyncOperation(*data)->SetAsyncMode(TRUE); |
230 } | 230 } |
231 | 231 |
232 void TabContentsDragWin::PrepareDragForFileContents( | 232 void WebContentsDragWin::PrepareDragForFileContents( |
233 const WebDropData& drop_data, ui::OSExchangeData* data) { | 233 const WebDropData& drop_data, ui::OSExchangeData* data) { |
234 static const int kMaxFilenameLength = 255; // FAT and NTFS | 234 static const int kMaxFilenameLength = 255; // FAT and NTFS |
235 FilePath file_name(drop_data.file_description_filename); | 235 FilePath file_name(drop_data.file_description_filename); |
236 string16 extension = file_name.Extension(); | 236 string16 extension = file_name.Extension(); |
237 file_name = file_name.BaseName().RemoveExtension(); | 237 file_name = file_name.BaseName().RemoveExtension(); |
238 // Images without ALT text will only have a file extension so we need to | 238 // Images without ALT text will only have a file extension so we need to |
239 // synthesize one from the provided extension and URL. | 239 // synthesize one from the provided extension and URL. |
240 if (file_name.value().empty()) { | 240 if (file_name.value().empty()) { |
241 // Retrieve the name from the URL. | 241 // Retrieve the name from the URL. |
242 file_name = FilePath( | 242 file_name = FilePath( |
243 net::GetSuggestedFilename(drop_data.url, "", "", "", "", "")); | 243 net::GetSuggestedFilename(drop_data.url, "", "", "", "", "")); |
244 if (file_name.value().size() + extension.size() > kMaxFilenameLength) { | 244 if (file_name.value().size() + extension.size() > kMaxFilenameLength) { |
245 file_name = FilePath(file_name.value().substr( | 245 file_name = FilePath(file_name.value().substr( |
246 0, kMaxFilenameLength - extension.size())); | 246 0, kMaxFilenameLength - extension.size())); |
247 } | 247 } |
248 } | 248 } |
249 file_name = file_name.ReplaceExtension(extension); | 249 file_name = file_name.ReplaceExtension(extension); |
250 data->SetFileContents(file_name, drop_data.file_contents); | 250 data->SetFileContents(file_name, drop_data.file_contents); |
251 } | 251 } |
252 | 252 |
253 void TabContentsDragWin::PrepareDragForUrl(const WebDropData& drop_data, | 253 void WebContentsDragWin::PrepareDragForUrl(const WebDropData& drop_data, |
254 ui::OSExchangeData* data) { | 254 ui::OSExchangeData* data) { |
255 if (drag_dest_->delegate()->AddDragData(drop_data, data)) | 255 if (drag_dest_->delegate()->AddDragData(drop_data, data)) |
256 return; | 256 return; |
257 | 257 |
258 data->SetURL(drop_data.url, drop_data.url_title); | 258 data->SetURL(drop_data.url, drop_data.url_title); |
259 } | 259 } |
260 | 260 |
261 void TabContentsDragWin::DoDragging(const WebDropData& drop_data, | 261 void WebContentsDragWin::DoDragging(const WebDropData& drop_data, |
262 WebDragOperationsMask ops, | 262 WebDragOperationsMask ops, |
263 const GURL& page_url, | 263 const GURL& page_url, |
264 const std::string& page_encoding, | 264 const std::string& page_encoding, |
265 const SkBitmap& image, | 265 const SkBitmap& image, |
266 const gfx::Point& image_offset) { | 266 const gfx::Point& image_offset) { |
267 ui::OSExchangeData data; | 267 ui::OSExchangeData data; |
268 | 268 |
269 // TODO(dcheng): Figure out why this is mutually exclusive. | 269 // TODO(dcheng): Figure out why this is mutually exclusive. |
270 if (!drop_data.download_metadata.empty()) { | 270 if (!drop_data.download_metadata.empty()) { |
271 PrepareDragForDownload(drop_data, &data, page_url, page_encoding); | 271 PrepareDragForDownload(drop_data, &data, page_url, page_encoding); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 drag_source_, | 309 drag_source_, |
310 web_drag_utils_win::WebDragOpMaskToWinDragOpMask(ops), | 310 web_drag_utils_win::WebDragOpMaskToWinDragOpMask(ops), |
311 &effect); | 311 &effect); |
312 } | 312 } |
313 | 313 |
314 // This works because WebDragSource::OnDragSourceDrop uses PostTask to | 314 // This works because WebDragSource::OnDragSourceDrop uses PostTask to |
315 // dispatch the actual event. | 315 // dispatch the actual event. |
316 drag_source_->set_effect(effect); | 316 drag_source_->set_effect(effect); |
317 } | 317 } |
318 | 318 |
319 void TabContentsDragWin::EndDragging(bool restore_suspended_state) { | 319 void WebContentsDragWin::EndDragging(bool restore_suspended_state) { |
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
321 | 321 |
322 if (drag_ended_) | 322 if (drag_ended_) |
323 return; | 323 return; |
324 drag_ended_ = true; | 324 drag_ended_ = true; |
325 | 325 |
326 if (restore_suspended_state) | 326 if (restore_suspended_state) |
327 drag_dest_->set_suspended(old_drop_target_suspended_state_); | 327 drag_dest_->set_suspended(old_drop_target_suspended_state_); |
328 | 328 |
329 if (msg_hook) { | 329 if (msg_hook) { |
330 AttachThreadInput(drag_out_thread_id, GetCurrentThreadId(), FALSE); | 330 AttachThreadInput(drag_out_thread_id, GetCurrentThreadId(), FALSE); |
331 UnhookWindowsHookEx(msg_hook); | 331 UnhookWindowsHookEx(msg_hook); |
332 msg_hook = NULL; | 332 msg_hook = NULL; |
333 } | 333 } |
334 | 334 |
335 drag_end_callback_.Run(); | 335 drag_end_callback_.Run(); |
336 } | 336 } |
337 | 337 |
338 void TabContentsDragWin::CancelDrag() { | 338 void WebContentsDragWin::CancelDrag() { |
339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
340 | 340 |
341 drag_source_->CancelDrag(); | 341 drag_source_->CancelDrag(); |
342 } | 342 } |
343 | 343 |
344 void TabContentsDragWin::CloseThread() { | 344 void WebContentsDragWin::CloseThread() { |
345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
346 | 346 |
347 drag_drop_thread_.reset(); | 347 drag_drop_thread_.reset(); |
348 } | 348 } |
349 | 349 |
350 void TabContentsDragWin::OnWaitForData() { | 350 void WebContentsDragWin::OnWaitForData() { |
351 DCHECK(drag_drop_thread_id_ == base::PlatformThread::CurrentId()); | 351 DCHECK(drag_drop_thread_id_ == base::PlatformThread::CurrentId()); |
352 | 352 |
353 // When the left button is release and we start to wait for the data, end | 353 // When the left button is release and we start to wait for the data, end |
354 // the dragging before DoDragDrop returns. This makes the page leave the drag | 354 // the dragging before DoDragDrop returns. This makes the page leave the drag |
355 // mode so that it can start to process the normal input events. | 355 // mode so that it can start to process the normal input events. |
356 BrowserThread::PostTask( | 356 BrowserThread::PostTask( |
357 BrowserThread::UI, | 357 BrowserThread::UI, |
358 FROM_HERE, | 358 FROM_HERE, |
359 base::Bind(&TabContentsDragWin::EndDragging, this, true)); | 359 base::Bind(&WebContentsDragWin::EndDragging, this, true)); |
360 } | 360 } |
361 | 361 |
362 void TabContentsDragWin::OnDataObjectDisposed() { | 362 void WebContentsDragWin::OnDataObjectDisposed() { |
363 DCHECK(drag_drop_thread_id_ == base::PlatformThread::CurrentId()); | 363 DCHECK(drag_drop_thread_id_ == base::PlatformThread::CurrentId()); |
364 | 364 |
365 // The drag-and-drop thread is only closed after OLE is done with | 365 // The drag-and-drop thread is only closed after OLE is done with |
366 // DataObjectImpl. | 366 // DataObjectImpl. |
367 BrowserThread::PostTask( | 367 BrowserThread::PostTask( |
368 BrowserThread::UI, | 368 BrowserThread::UI, |
369 FROM_HERE, | 369 FROM_HERE, |
370 base::Bind(&TabContentsDragWin::CloseThread, this)); | 370 base::Bind(&WebContentsDragWin::CloseThread, this)); |
371 } | 371 } |
OLD | NEW |