Skip to content

Commit a03d21c

Browse files
authored
Improve clipboard without cbhm (#65)
1 parent 3a43fb5 commit a03d21c

File tree

5 files changed

+261
-16
lines changed

5 files changed

+261
-16
lines changed

flutter/shell/platform/tizen/BUILD.gn

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ template("embedder") {
175175
if (api_version == "6.5" && target_name != "flutter_tizen_wearable") {
176176
sources += [
177177
"flutter_tizen_nui.cc",
178+
"tizen_clipboard.cc",
178179
"tizen_view_nui.cc",
179180
]
180181

@@ -183,7 +184,10 @@ template("embedder") {
183184
"dali2-core",
184185
]
185186

186-
defines += [ "NUI_SUPPORT" ]
187+
defines += [
188+
"NUI_SUPPORT",
189+
"CLIPBOARD_SUPPORT",
190+
]
187191
}
188192

189193
configs += [

flutter/shell/platform/tizen/channels/platform_channel.cc

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ PlatformChannel::PlatformChannel(BinaryMessenger* messenger,
8181
kChannelName,
8282
&JsonMethodCodec::GetInstance())),
8383
view_(view) {
84+
#ifdef CLIPBOARD_SUPPORT
85+
tizen_clipboard_ = std::make_unique<TizenClipboard>(view);
86+
#endif
87+
8488
channel_->SetMethodCallHandler(
8589
[this](const MethodCall<rapidjson::Document>& call,
8690
std::unique_ptr<MethodResult<rapidjson::Document>> result) {
@@ -117,15 +121,27 @@ void PlatformChannel::HandleMethodCall(
117121
"Clipboard API only supports text.");
118122
return;
119123
}
120-
GetClipboardData([result = result.release()](const std::string& data) {
121-
rapidjson::Document document;
122-
document.SetObject();
123-
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
124-
document.AddMember(rapidjson::Value(kTextKey, allocator),
125-
rapidjson::Value(data, allocator), allocator);
126-
result->Success(document);
127-
delete result;
128-
});
124+
auto* result_ptr = result.release();
125+
if (!GetClipboardData([result_ptr](std::optional<std::string> data) {
126+
if (!data.has_value()) {
127+
result_ptr->Error(kUnknownClipboardError, "Internal error.");
128+
delete result_ptr;
129+
return;
130+
}
131+
132+
rapidjson::Document document;
133+
document.SetObject();
134+
rapidjson::Document::AllocatorType& allocator =
135+
document.GetAllocator();
136+
document.AddMember(rapidjson::Value(kTextKey, allocator),
137+
rapidjson::Value(data.value(), allocator),
138+
allocator);
139+
result_ptr->Success(document);
140+
delete result_ptr;
141+
})) {
142+
result_ptr->Error(kUnknownClipboardError, "Internal error.");
143+
delete result_ptr;
144+
};
129145
} else if (method == kSetClipboardDataMethod) {
130146
const rapidjson::Value& document = *arguments;
131147
auto iter = document.FindMember(kTextKey);
@@ -219,16 +235,29 @@ void PlatformChannel::HapticFeedbackVibrate(const std::string& feedback_type) {
219235
FeedbackManager::GetInstance().Vibrate();
220236
}
221237

222-
void PlatformChannel::GetClipboardData(ClipboardCallback on_data) {
238+
bool PlatformChannel::GetClipboardData(ClipboardCallback on_data) {
239+
#ifdef CLIPBOARD_SUPPORT
240+
return tizen_clipboard_->GetData(std::move(on_data));
241+
#else
223242
on_data(clipboard_);
243+
return true;
244+
#endif
224245
}
225246

226247
void PlatformChannel::SetClipboardData(const std::string& data) {
248+
#ifdef CLIPBOARD_SUPPORT
249+
tizen_clipboard_->SetData(data);
250+
#else
227251
clipboard_ = data;
252+
#endif
228253
}
229254

230255
bool PlatformChannel::ClipboardHasStrings() {
256+
#ifdef CLIPBOARD_SUPPORT
257+
return tizen_clipboard_->HasStrings();
258+
#else
231259
return !clipboard_.empty();
260+
#endif
232261
}
233262

234263
void PlatformChannel::RestoreSystemUiOverlays() {

flutter/shell/platform/tizen/channels/platform_channel.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77

88
#include <functional>
99
#include <memory>
10+
#include <optional>
1011
#include <string>
1112
#include <vector>
1213

1314
#include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h"
1415
#include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h"
16+
#ifdef CLIPBOARD_SUPPORT
17+
#include "flutter/shell/platform/tizen/tizen_clipboard.h"
18+
#endif
1519
#include "flutter/shell/platform/tizen/tizen_view_base.h"
1620
#include "rapidjson/document.h"
1721

@@ -23,7 +27,8 @@ class PlatformChannel {
2327
virtual ~PlatformChannel();
2428

2529
private:
26-
using ClipboardCallback = std::function<void(const std::string& data)>;
30+
using ClipboardCallback =
31+
std::function<void(std::optional<std::string> data)>;
2732

2833
void HandleMethodCall(
2934
const MethodCall<rapidjson::Document>& call,
@@ -32,7 +37,7 @@ class PlatformChannel {
3237
void SystemNavigatorPop();
3338
void PlaySystemSound(const std::string& sound_type);
3439
void HapticFeedbackVibrate(const std::string& feedback_type);
35-
void GetClipboardData(ClipboardCallback on_data);
40+
bool GetClipboardData(ClipboardCallback on_data);
3641
void SetClipboardData(const std::string& data);
3742
bool ClipboardHasStrings();
3843
void RestoreSystemUiOverlays();
@@ -48,11 +53,12 @@ class PlatformChannel {
4853

4954
// A reference to the native view managed by FlutterTizenView.
5055
TizenViewBase* view_ = nullptr;
51-
56+
#ifdef CLIPBOARD_SUPPORT
57+
std::unique_ptr<TizenClipboard> tizen_clipboard_;
58+
#else
5259
// A container that holds clipboard data during the engine lifetime.
53-
//
54-
// TODO(JSUYA): Remove after implementing the ecore_wl2 based clipboard.
5560
std::string clipboard_;
61+
#endif
5662
};
5763

5864
} // namespace flutter
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright 2024 Samsung Electronics Co., Ltd. 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 "tizen_clipboard.h"
6+
7+
#include "flutter/shell/platform/tizen/logger.h"
8+
#include "flutter/shell/platform/tizen/tizen_window.h"
9+
#include "flutter/shell/platform/tizen/tizen_window_ecore_wl2.h"
10+
11+
namespace flutter {
12+
13+
namespace {
14+
15+
constexpr char kMimeTypeTextPlain[] = "text/plain;charset=utf-8";
16+
17+
} // namespace
18+
19+
TizenClipboard::TizenClipboard(TizenViewBase* view) {
20+
if (auto* window = dynamic_cast<TizenWindowEcoreWl2*>(view)) {
21+
auto* ecore_wl2_window =
22+
static_cast<Ecore_Wl2_Window*>(window->GetNativeHandle());
23+
display_ = ecore_wl2_window_display_get(ecore_wl2_window);
24+
} else {
25+
display_ = ecore_wl2_connected_display_get(NULL);
26+
}
27+
28+
send_handler = ecore_event_handler_add(
29+
ECORE_WL2_EVENT_DATA_SOURCE_SEND,
30+
[](void* data, int type, void* event) -> Eina_Bool {
31+
auto* self = reinterpret_cast<TizenClipboard*>(data);
32+
self->SendData(event);
33+
return ECORE_CALLBACK_PASS_ON;
34+
},
35+
this);
36+
receive_handler = ecore_event_handler_add(
37+
ECORE_WL2_EVENT_OFFER_DATA_READY,
38+
[](void* data, int type, void* event) -> Eina_Bool {
39+
auto* self = reinterpret_cast<TizenClipboard*>(data);
40+
self->ReceiveData(event);
41+
return ECORE_CALLBACK_PASS_ON;
42+
},
43+
this);
44+
}
45+
46+
TizenClipboard::~TizenClipboard() {
47+
ecore_event_handler_del(send_handler);
48+
ecore_event_handler_del(receive_handler);
49+
}
50+
51+
void TizenClipboard::SendData(void* event) {
52+
auto* send_event = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
53+
if (!send_event->type || strcmp(send_event->type, kMimeTypeTextPlain)) {
54+
FT_LOG(Error) << "Invaild mime type.";
55+
return;
56+
}
57+
58+
if (send_event->serial != selection_serial_) {
59+
FT_LOG(Error) << "The serial doesn't match.";
60+
return;
61+
}
62+
63+
write(send_event->fd, data_.c_str(), data_.length());
64+
close(send_event->fd);
65+
}
66+
67+
void TizenClipboard::ReceiveData(void* event) {
68+
auto* ready_event =
69+
reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
70+
if (ready_event->data == nullptr || ready_event->len < 1) {
71+
FT_LOG(Info) << "No data available.";
72+
if (on_data_callback_) {
73+
on_data_callback_("");
74+
on_data_callback_ = nullptr;
75+
}
76+
return;
77+
}
78+
79+
if (ready_event->offer != selection_offer_) {
80+
FT_LOG(Error) << "The offer doesn't match.";
81+
if (on_data_callback_) {
82+
on_data_callback_(std::nullopt);
83+
on_data_callback_ = nullptr;
84+
}
85+
return;
86+
}
87+
88+
size_t data_length = strlen(ready_event->data);
89+
size_t buffer_size = ready_event->len;
90+
std::string content;
91+
92+
if (data_length < buffer_size) {
93+
content.append(ready_event->data, data_length);
94+
} else {
95+
content.append(ready_event->data, buffer_size);
96+
}
97+
98+
if (on_data_callback_) {
99+
on_data_callback_(content);
100+
on_data_callback_ = nullptr;
101+
}
102+
}
103+
104+
void TizenClipboard::SetData(const std::string& data) {
105+
data_ = data;
106+
107+
const char* mime_types[3];
108+
mime_types[0] = kMimeTypeTextPlain;
109+
// TODO(jsuya): There is an issue where ECORE_WL2_EVENT_DATA_SOURCE_SEND event
110+
// does not work properly even if ecore_wl2_dnd_selection_set() is called in
111+
// Tizen 6.5 or lower. Therefore, add empty mimetype for event call from the
112+
// cbhm module. Since it works normally from Tizen 8.0, this part may be
113+
// modified in the future.
114+
mime_types[1] = "";
115+
mime_types[2] = nullptr;
116+
117+
Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_);
118+
selection_serial_ = ecore_wl2_dnd_selection_set(input, mime_types);
119+
ecore_wl2_display_flush(display_);
120+
}
121+
122+
bool TizenClipboard::GetData(ClipboardCallback on_data_callback) {
123+
on_data_callback_ = std::move(on_data_callback);
124+
125+
Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_);
126+
selection_offer_ = ecore_wl2_dnd_selection_get(input);
127+
128+
if (!selection_offer_) {
129+
FT_LOG(Error) << "ecore_wl2_dnd_selection_get() failed.";
130+
return false;
131+
}
132+
133+
ecore_wl2_offer_receive(selection_offer_,
134+
const_cast<char*>(kMimeTypeTextPlain));
135+
return true;
136+
}
137+
138+
bool TizenClipboard::HasStrings() {
139+
Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display_);
140+
selection_offer_ = ecore_wl2_dnd_selection_get(input);
141+
142+
if (!selection_offer_) {
143+
FT_LOG(Error) << "ecore_wl2_dnd_selection_get() failed.";
144+
return false;
145+
}
146+
147+
Eina_Array* available_types = ecore_wl2_offer_mimes_get(selection_offer_);
148+
unsigned int type_count = eina_array_count(available_types);
149+
150+
for (unsigned int i = 0; i < type_count; ++i) {
151+
auto* available_type =
152+
static_cast<char*>(eina_array_data_get(available_types, i));
153+
if (!strcmp(kMimeTypeTextPlain, available_type)) {
154+
return true;
155+
}
156+
}
157+
return false;
158+
}
159+
160+
} // namespace flutter
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2024 Samsung Electronics Co., Ltd. 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+
#ifndef EMBEDDER_TIZEN_CLIPBOARD_H_
6+
#define EMBEDDER_TIZEN_CLIPBOARD_H_
7+
8+
#define EFL_BETA_API_SUPPORT
9+
#include <Ecore_Wl2.h>
10+
11+
#include <functional>
12+
#include <optional>
13+
#include <string>
14+
15+
#include "flutter/shell/platform/tizen/tizen_view_base.h"
16+
17+
namespace flutter {
18+
19+
class TizenClipboard {
20+
public:
21+
using ClipboardCallback =
22+
std::function<void(std::optional<std::string> data)>;
23+
24+
TizenClipboard(TizenViewBase* view);
25+
virtual ~TizenClipboard();
26+
27+
void SetData(const std::string& data);
28+
bool GetData(ClipboardCallback on_data_callback);
29+
bool HasStrings();
30+
31+
private:
32+
void SendData(void* event);
33+
void ReceiveData(void* event);
34+
35+
std::string data_;
36+
ClipboardCallback on_data_callback_;
37+
uint32_t selection_serial_ = 0;
38+
Ecore_Wl2_Offer* selection_offer_ = nullptr;
39+
Ecore_Wl2_Display* display_ = nullptr;
40+
Ecore_Event_Handler* send_handler = nullptr;
41+
Ecore_Event_Handler* receive_handler = nullptr;
42+
};
43+
44+
} // namespace flutter
45+
46+
#endif // EMBEDDER_TIZEN_CLIPBOARD_H_

0 commit comments

Comments
 (0)