1 // Copyright 2014 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.
5 #include "remoting/host/chromeos/clipboard_aura.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/timer/timer.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "remoting/base/constants.h"
11 #include "remoting/proto/event.pb.h"
12 #include "remoting/protocol/clipboard_stub.h"
13 #include "ui/base/clipboard/clipboard.h"
14 #include "ui/base/clipboard/scoped_clipboard_writer.h"
18 // Clipboard polling interval in milliseconds.
19 const int64 kClipboardPollingIntervalMs
= 500;
25 class ClipboardAura::Core
{
29 // Mirror the public interface.
30 void Start(scoped_ptr
<protocol::ClipboardStub
> client_clipboard
);
31 void InjectClipboardEvent(const protocol::ClipboardEvent
& event
);
34 // Overrides the clipboard polling interval for unit test.
35 void SetPollingIntervalForTesting(base::TimeDelta polling_interval
);
38 void CheckClipboardForChanges();
40 scoped_ptr
<protocol::ClipboardStub
> client_clipboard_
;
41 scoped_ptr
<base::RepeatingTimer
<Core
>> clipboard_polling_timer_
;
42 uint64 current_change_count_
;
43 base::TimeDelta polling_interval_
;
45 DISALLOW_COPY_AND_ASSIGN(Core
);
48 ClipboardAura::ClipboardAura(
49 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
)
51 ui_task_runner_(ui_task_runner
) {
54 ClipboardAura::~ClipboardAura() {
55 ui_task_runner_
->DeleteSoon(FROM_HERE
, core_
.release());
58 void ClipboardAura::Start(
59 scoped_ptr
<protocol::ClipboardStub
> client_clipboard
) {
60 ui_task_runner_
->PostTask(
61 FROM_HERE
, base::Bind(&Core::Start
, base::Unretained(core_
.get()),
62 base::Passed(&client_clipboard
)));
65 void ClipboardAura::InjectClipboardEvent(
66 const protocol::ClipboardEvent
& event
) {
67 ui_task_runner_
->PostTask(FROM_HERE
,
68 base::Bind(&Core::InjectClipboardEvent
,
69 base::Unretained(core_
.get()), event
));
72 void ClipboardAura::Stop() {
73 ui_task_runner_
->PostTask(
74 FROM_HERE
, base::Bind(&Core::Stop
, base::Unretained(core_
.get())));
77 void ClipboardAura::SetPollingIntervalForTesting(
78 base::TimeDelta polling_interval
) {
79 core_
->SetPollingIntervalForTesting(polling_interval
);
82 ClipboardAura::Core::Core()
83 : current_change_count_(0),
85 base::TimeDelta::FromMilliseconds(kClipboardPollingIntervalMs
)) {
88 void ClipboardAura::Core::Start(
89 scoped_ptr
<protocol::ClipboardStub
> client_clipboard
) {
90 client_clipboard_
.reset(client_clipboard
.release());
92 // Aura doesn't provide a clipboard-changed notification. The only way to
93 // detect clipboard changes is by polling.
94 clipboard_polling_timer_
.reset(new base::RepeatingTimer
<Core
>());
95 clipboard_polling_timer_
->Start(
96 FROM_HERE
, polling_interval_
, this,
97 &ClipboardAura::Core::CheckClipboardForChanges
);
100 void ClipboardAura::Core::InjectClipboardEvent(
101 const protocol::ClipboardEvent
& event
) {
102 // Currently we only handle UTF-8 text.
103 if (event
.mime_type().compare(kMimeTypeTextUtf8
) != 0) {
107 ui::ScopedClipboardWriter
clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE
);
108 clipboard_writer
.WriteText(base::UTF8ToUTF16(event
.data()));
110 // Update local change-count to prevent this change from being picked up by
111 // CheckClipboardForChanges.
112 current_change_count_
++;
115 void ClipboardAura::Core::Stop() {
116 clipboard_polling_timer_
.reset();
117 client_clipboard_
.reset();
120 void ClipboardAura::Core::SetPollingIntervalForTesting(
121 base::TimeDelta polling_interval
) {
122 polling_interval_
= polling_interval
;
125 void ClipboardAura::Core::CheckClipboardForChanges() {
126 ui::Clipboard
* clipboard
= ui::Clipboard::GetForCurrentThread();
127 uint64 change_count
=
128 clipboard
->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE
);
130 if (change_count
== current_change_count_
) {
134 current_change_count_
= change_count
;
136 protocol::ClipboardEvent event
;
139 clipboard
->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE
, &data
);
140 event
.set_mime_type(kMimeTypeTextUtf8
);
141 event
.set_data(data
);
143 client_clipboard_
->InjectClipboardEvent(event
);
146 scoped_ptr
<Clipboard
> Clipboard::Create() {
147 return make_scoped_ptr(
148 new ClipboardAura(content::BrowserThread::GetMessageLoopProxyForThread(
149 content::BrowserThread::UI
)));
152 } // namespace remoting