Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / clipboard_mac.mm
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
3 // found in the LICENSE file.
4
5 #include "remoting/host/clipboard.h"
6
7 #import <Cocoa/Cocoa.h>
8
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/timer/timer.h"
14 #include "remoting/base/constants.h"
15 #include "remoting/base/util.h"
16 #include "remoting/proto/event.pb.h"
17 #include "remoting/protocol/clipboard_stub.h"
18
19 namespace {
20
21 // Clipboard polling interval in milliseconds.
22 const int64 kClipboardPollingIntervalMs = 500;
23
24 } // namespace
25
26 namespace remoting {
27
28 class ClipboardMac : public Clipboard {
29  public:
30   ClipboardMac();
31   ~ClipboardMac() override;
32
33   // Must be called on the UI thread.
34   void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard) override;
35   void InjectClipboardEvent(const protocol::ClipboardEvent& event) override;
36   void Stop() override;
37
38  private:
39   void CheckClipboardForChanges();
40
41   scoped_ptr<protocol::ClipboardStub> client_clipboard_;
42   scoped_ptr<base::RepeatingTimer<ClipboardMac> > clipboard_polling_timer_;
43   NSInteger current_change_count_;
44
45   DISALLOW_COPY_AND_ASSIGN(ClipboardMac);
46 };
47
48 ClipboardMac::ClipboardMac() : current_change_count_(0) {
49 }
50
51 ClipboardMac::~ClipboardMac() {
52   // In it2me the destructor is not called in the same thread that the timer is
53   // created. Thus the timer must have already been destroyed by now.
54   DCHECK(clipboard_polling_timer_.get() == NULL);
55 }
56
57 void ClipboardMac::Start(scoped_ptr<protocol::ClipboardStub> client_clipboard) {
58   client_clipboard_.reset(client_clipboard.release());
59
60   // Synchronize local change-count with the pasteboard's. The change-count is
61   // used to detect clipboard changes.
62   current_change_count_ = [[NSPasteboard generalPasteboard] changeCount];
63
64   // OS X doesn't provide a clipboard-changed notification. The only way to
65   // detect clipboard changes is by polling.
66   clipboard_polling_timer_.reset(new base::RepeatingTimer<ClipboardMac>());
67   clipboard_polling_timer_->Start(FROM_HERE,
68       base::TimeDelta::FromMilliseconds(kClipboardPollingIntervalMs),
69       this, &ClipboardMac::CheckClipboardForChanges);
70 }
71
72 void ClipboardMac::InjectClipboardEvent(const protocol::ClipboardEvent& event) {
73   // Currently we only handle UTF-8 text.
74   if (event.mime_type().compare(kMimeTypeTextUtf8) != 0)
75     return;
76   if (!StringIsUtf8(event.data().c_str(), event.data().length())) {
77     LOG(ERROR) << "ClipboardEvent data is not UTF-8 encoded.";
78     return;
79   }
80
81   // Write UTF-8 text to clipboard.
82   NSString* text = base::SysUTF8ToNSString(event.data());
83   NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
84   [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType]
85                      owner:nil];
86   [pasteboard setString:text forType:NSStringPboardType];
87
88   // Update local change-count to prevent this change from being picked up by
89   // CheckClipboardForChanges.
90   current_change_count_ = [[NSPasteboard generalPasteboard] changeCount];
91 }
92
93 void ClipboardMac::Stop() {
94   clipboard_polling_timer_.reset();
95   client_clipboard_.reset();
96 }
97
98 void ClipboardMac::CheckClipboardForChanges() {
99   NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
100   NSInteger change_count = [pasteboard changeCount];
101   if (change_count == current_change_count_) {
102     return;
103   }
104   current_change_count_ = change_count;
105
106   NSString* data = [pasteboard stringForType:NSStringPboardType];
107   if (data == nil) {
108     return;
109   }
110
111   protocol::ClipboardEvent event;
112   event.set_mime_type(kMimeTypeTextUtf8);
113   event.set_data(base::SysNSStringToUTF8(data));
114   client_clipboard_->InjectClipboardEvent(event);
115 }
116
117 scoped_ptr<Clipboard> Clipboard::Create() {
118   return make_scoped_ptr(new ClipboardMac());
119 }
120
121 }  // namespace remoting