OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 // Many of these functions are based on those found in | 5 // Many of these functions are based on those found in |
6 // webkit/port/platform/PasteboardWin.cpp | 6 // webkit/port/platform/PasteboardWin.cpp |
7 | 7 |
8 #include <shlobj.h> | 8 #include <shlobj.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 | 10 |
11 #include "base/clipboard.h" | 11 #include "base/clipboard.h" |
12 | 12 |
13 #include "base/clipboard_util.h" | 13 #include "base/clipboard_util.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
19 // A small object to ensure we close the clipboard after opening it. | 19 // A scoper to manage acquiring and automatically releasing the clipboard. |
20 class ClipboardLock { | 20 class ScopedClipboard { |
21 public: | 21 public: |
22 ClipboardLock() : we_own_the_lock_(false) { } | 22 ScopedClipboard() : opened_(false) { } |
23 | 23 |
24 ~ClipboardLock() { | 24 ~ScopedClipboard() { |
25 if (we_own_the_lock_) | 25 if (opened_) |
26 Release(); | 26 Release(); |
27 } | 27 } |
28 | 28 |
29 bool Acquire(HWND owner) { | 29 bool Acquire(HWND owner) { |
30 // We shouldn't be calling this if we already own the clipboard lock. | |
31 DCHECK(!we_own_the_lock_); | |
32 | |
33 // We already have the lock. We don't want to stomp on the other use. | |
34 if (we_own_the_lock_) | |
35 return false; | |
36 | |
37 const int kMaxAttemptsToOpenClipboard = 5; | 30 const int kMaxAttemptsToOpenClipboard = 5; |
38 | 31 |
39 // Attempt to acquire the clipboard lock. This may fail if another process | 32 if (opened_) { |
40 // currently holds the lock. We're willing to try a few times in the hopes | 33 NOTREACHED(); |
41 // of acquiring it. | 34 return false; |
| 35 } |
| 36 |
| 37 // Attempt to open the clipboard, which will acquire the Windows clipboard |
| 38 // lock. This may fail if another process currently holds this lock. |
| 39 // We're willing to try a few times in the hopes of acquiring it. |
42 // | 40 // |
43 // This turns out to be an issue when using remote desktop because the | 41 // This turns out to be an issue when using remote desktop because the |
44 // rdpclip.exe process likes to read what we've written to the clipboard and | 42 // rdpclip.exe process likes to read what we've written to the clipboard and |
45 // send it to the RDP client. If we open and close the clipboard in quick | 43 // send it to the RDP client. If we open and close the clipboard in quick |
46 // succession, we might be trying to open it while rdpclip.exe has it open, | 44 // succession, we might be trying to open it while rdpclip.exe has it open, |
47 // See Bug 815425. | 45 // See Bug 815425. |
48 // | 46 // |
49 // In fact, we believe we'll only spin this loop over remote desktop. In | 47 // In fact, we believe we'll only spin this loop over remote desktop. In |
50 // normal situations, the user is initiating clipboard operations and there | 48 // normal situations, the user is initiating clipboard operations and there |
51 // shouldn't be lock contention. | 49 // shouldn't be contention. |
52 | 50 |
53 for (int attempts = 0; attempts < kMaxAttemptsToOpenClipboard; ++attempts) { | 51 for (int attempts = 0; attempts < kMaxAttemptsToOpenClipboard; ++attempts) { |
| 52 // If we didn't manage to open the clipboard, sleep a bit and be hopeful. |
| 53 if (attempts != 0) |
| 54 ::Sleep(5); |
| 55 |
54 if (::OpenClipboard(owner)) { | 56 if (::OpenClipboard(owner)) { |
55 we_own_the_lock_ = true; | 57 opened_ = true; |
56 return we_own_the_lock_; | 58 return true; |
57 } | 59 } |
58 | |
59 // Having failed, we yield our timeslice to other processes. ::Yield seems | |
60 // to be insufficient here, so we sleep for 5 ms. | |
61 if (attempts < (kMaxAttemptsToOpenClipboard - 1)) | |
62 ::Sleep(5); | |
63 } | 60 } |
64 | 61 |
65 // We failed to acquire the clipboard. | 62 // We failed to acquire the clipboard. |
66 return false; | 63 return false; |
67 } | 64 } |
68 | 65 |
69 void Release() { | 66 void Release() { |
70 // We should only be calling this if we already own the clipboard lock. | 67 if (opened_) { |
71 DCHECK(we_own_the_lock_); | 68 ::CloseClipboard(); |
72 | 69 opened_ = false; |
73 // We we don't have the lock, there is nothing to release. | 70 } else { |
74 if (!we_own_the_lock_) | 71 NOTREACHED(); |
75 return; | 72 } |
76 | |
77 ::CloseClipboard(); | |
78 we_own_the_lock_ = false; | |
79 } | 73 } |
80 | 74 |
81 private: | 75 private: |
82 bool we_own_the_lock_; | 76 bool opened_; |
83 }; | 77 }; |
84 | 78 |
85 LRESULT CALLBACK ClipboardOwnerWndProc(HWND hwnd, | 79 LRESULT CALLBACK ClipboardOwnerWndProc(HWND hwnd, |
86 UINT message, | 80 UINT message, |
87 WPARAM wparam, | 81 WPARAM wparam, |
88 LPARAM lparam) { | 82 LPARAM lparam) { |
89 LRESULT lresult = 0; | 83 LRESULT lresult = 0; |
90 | 84 |
91 switch(message) { | 85 switch(message) { |
92 case WM_RENDERFORMAT: | 86 case WM_RENDERFORMAT: |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 Clipboard::~Clipboard() { | 141 Clipboard::~Clipboard() { |
148 ::DestroyWindow(clipboard_owner_); | 142 ::DestroyWindow(clipboard_owner_); |
149 clipboard_owner_ = NULL; | 143 clipboard_owner_ = NULL; |
150 } | 144 } |
151 | 145 |
152 void Clipboard::WriteObjects(const ObjectMap& objects) { | 146 void Clipboard::WriteObjects(const ObjectMap& objects) { |
153 WriteObjects(objects, NULL); | 147 WriteObjects(objects, NULL); |
154 } | 148 } |
155 | 149 |
156 void Clipboard::WriteObjects(const ObjectMap& objects, ProcessHandle process) { | 150 void Clipboard::WriteObjects(const ObjectMap& objects, ProcessHandle process) { |
157 ClipboardLock lock; | 151 ScopedClipboard clipboard; |
158 if (!lock.Acquire(clipboard_owner_)) | 152 if (!clipboard.Acquire(clipboard_owner_)) |
159 return; | 153 return; |
160 | 154 |
161 ::EmptyClipboard(); | 155 ::EmptyClipboard(); |
162 | 156 |
163 for (ObjectMap::const_iterator iter = objects.begin(); | 157 for (ObjectMap::const_iterator iter = objects.begin(); |
164 iter != objects.end(); ++iter) { | 158 iter != objects.end(); ++iter) { |
165 if (iter->first == CBF_SMBITMAP) | 159 if (iter->first == CBF_SMBITMAP) |
166 WriteBitmapFromSharedMemory(&(iter->second[0].front()), | 160 WriteBitmapFromSharedMemory(&(iter->second[0].front()), |
167 &(iter->second[1].front()), | 161 &(iter->second[1].front()), |
168 process); | 162 process); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 | 377 |
384 void Clipboard::ReadText(std::wstring* result) const { | 378 void Clipboard::ReadText(std::wstring* result) const { |
385 if (!result) { | 379 if (!result) { |
386 NOTREACHED(); | 380 NOTREACHED(); |
387 return; | 381 return; |
388 } | 382 } |
389 | 383 |
390 result->clear(); | 384 result->clear(); |
391 | 385 |
392 // Acquire the clipboard. | 386 // Acquire the clipboard. |
393 ClipboardLock lock; | 387 ScopedClipboard clipboard; |
394 if (!lock.Acquire(clipboard_owner_)) | 388 if (!clipboard.Acquire(clipboard_owner_)) |
395 return; | 389 return; |
396 | 390 |
397 HANDLE data = ::GetClipboardData(CF_UNICODETEXT); | 391 HANDLE data = ::GetClipboardData(CF_UNICODETEXT); |
398 if (!data) | 392 if (!data) |
399 return; | 393 return; |
400 | 394 |
401 result->assign(static_cast<const wchar_t*>(::GlobalLock(data))); | 395 result->assign(static_cast<const wchar_t*>(::GlobalLock(data))); |
402 ::GlobalUnlock(data); | 396 ::GlobalUnlock(data); |
403 } | 397 } |
404 | 398 |
405 void Clipboard::ReadAsciiText(std::string* result) const { | 399 void Clipboard::ReadAsciiText(std::string* result) const { |
406 if (!result) { | 400 if (!result) { |
407 NOTREACHED(); | 401 NOTREACHED(); |
408 return; | 402 return; |
409 } | 403 } |
410 | 404 |
411 result->clear(); | 405 result->clear(); |
412 | 406 |
413 // Acquire the clipboard. | 407 // Acquire the clipboard. |
414 ClipboardLock lock; | 408 ScopedClipboard clipboard; |
415 if (!lock.Acquire(clipboard_owner_)) | 409 if (!clipboard.Acquire(clipboard_owner_)) |
416 return; | 410 return; |
417 | 411 |
418 HANDLE data = ::GetClipboardData(CF_TEXT); | 412 HANDLE data = ::GetClipboardData(CF_TEXT); |
419 if (!data) | 413 if (!data) |
420 return; | 414 return; |
421 | 415 |
422 result->assign(static_cast<const char*>(::GlobalLock(data))); | 416 result->assign(static_cast<const char*>(::GlobalLock(data))); |
423 ::GlobalUnlock(data); | 417 ::GlobalUnlock(data); |
424 } | 418 } |
425 | 419 |
426 void Clipboard::ReadHTML(std::wstring* markup, std::string* src_url) const { | 420 void Clipboard::ReadHTML(std::wstring* markup, std::string* src_url) const { |
427 if (markup) | 421 if (markup) |
428 markup->clear(); | 422 markup->clear(); |
429 | 423 |
430 if (src_url) | 424 if (src_url) |
431 src_url->clear(); | 425 src_url->clear(); |
432 | 426 |
433 // Acquire the clipboard. | 427 // Acquire the clipboard. |
434 ClipboardLock lock; | 428 ScopedClipboard clipboard; |
435 if (!lock.Acquire(clipboard_owner_)) | 429 if (!clipboard.Acquire(clipboard_owner_)) |
436 return; | 430 return; |
437 | 431 |
438 HANDLE data = ::GetClipboardData(GetHtmlFormatType()); | 432 HANDLE data = ::GetClipboardData(GetHtmlFormatType()); |
439 if (!data) | 433 if (!data) |
440 return; | 434 return; |
441 | 435 |
442 std::string html_fragment(static_cast<const char*>(::GlobalLock(data))); | 436 std::string html_fragment(static_cast<const char*>(::GlobalLock(data))); |
443 ::GlobalUnlock(data); | 437 ::GlobalUnlock(data); |
444 | 438 |
445 ParseHTMLClipboardFormat(html_fragment, markup, src_url); | 439 ParseHTMLClipboardFormat(html_fragment, markup, src_url); |
446 } | 440 } |
447 | 441 |
448 void Clipboard::ReadBookmark(std::wstring* title, std::string* url) const { | 442 void Clipboard::ReadBookmark(std::wstring* title, std::string* url) const { |
449 if (title) | 443 if (title) |
450 title->clear(); | 444 title->clear(); |
451 | 445 |
452 if (url) | 446 if (url) |
453 url->clear(); | 447 url->clear(); |
454 | 448 |
455 // Acquire the clipboard. | 449 // Acquire the clipboard. |
456 ClipboardLock lock; | 450 ScopedClipboard clipboard; |
457 if (!lock.Acquire(clipboard_owner_)) | 451 if (!clipboard.Acquire(clipboard_owner_)) |
458 return; | 452 return; |
459 | 453 |
460 HANDLE data = ::GetClipboardData(GetUrlWFormatType()); | 454 HANDLE data = ::GetClipboardData(GetUrlWFormatType()); |
461 if (!data) | 455 if (!data) |
462 return; | 456 return; |
463 | 457 |
464 std::wstring bookmark(static_cast<const wchar_t*>(::GlobalLock(data))); | 458 std::wstring bookmark(static_cast<const wchar_t*>(::GlobalLock(data))); |
465 ::GlobalUnlock(data); | 459 ::GlobalUnlock(data); |
466 | 460 |
467 ParseBookmarkClipboardFormat(bookmark, title, url); | 461 ParseBookmarkClipboardFormat(bookmark, title, url); |
(...skipping 17 matching lines...) Expand all Loading... |
485 | 479 |
486 // Read a set of files in HDROP format from the clipboard. | 480 // Read a set of files in HDROP format from the clipboard. |
487 void Clipboard::ReadFiles(std::vector<std::wstring>* files) const { | 481 void Clipboard::ReadFiles(std::vector<std::wstring>* files) const { |
488 if (!files) { | 482 if (!files) { |
489 NOTREACHED(); | 483 NOTREACHED(); |
490 return; | 484 return; |
491 } | 485 } |
492 | 486 |
493 files->clear(); | 487 files->clear(); |
494 | 488 |
495 ClipboardLock lock; | 489 ScopedClipboard clipboard; |
496 if (!lock.Acquire(clipboard_owner_)) | 490 if (!clipboard.Acquire(clipboard_owner_)) |
497 return; | 491 return; |
498 | 492 |
499 HDROP drop = static_cast<HDROP>(::GetClipboardData(CF_HDROP)); | 493 HDROP drop = static_cast<HDROP>(::GetClipboardData(CF_HDROP)); |
500 if (!drop) | 494 if (!drop) |
501 return; | 495 return; |
502 | 496 |
503 // Count of files in the HDROP. | 497 // Count of files in the HDROP. |
504 int count = ::DragQueryFile(drop, 0xffffffff, NULL, 0); | 498 int count = ::DragQueryFile(drop, 0xffffffff, NULL, 0); |
505 | 499 |
506 if (count) { | 500 if (count) { |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 return ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat; | 694 return ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat; |
701 } | 695 } |
702 | 696 |
703 // static | 697 // static |
704 void Clipboard::FreeData(FormatType format, HANDLE data) { | 698 void Clipboard::FreeData(FormatType format, HANDLE data) { |
705 if (format == CF_BITMAP) | 699 if (format == CF_BITMAP) |
706 ::DeleteObject(static_cast<HBITMAP>(data)); | 700 ::DeleteObject(static_cast<HBITMAP>(data)); |
707 else | 701 else |
708 ::GlobalFree(data); | 702 ::GlobalFree(data); |
709 } | 703 } |
OLD | NEW |