| 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 |