[dali_2.3.31] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / clipboard / ubuntu-x11 / clipboard-impl-x.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/clipboard/common/clipboard-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/internal/system/linux/dali-ecore-x.h>
24 #include <dali/public-api/adaptor-framework/timer.h>
25 #include <dali/public-api/object/any.h>
26 #include <dali/public-api/object/type-registry.h>
27
28 // INTERNAL INCLUDES
29 #include <dali/devel-api/common/singleton-service.h>
30 #include <dali/internal/adaptor/common/adaptor-impl.h>
31 #include <dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h>
32 #include <map>
33 #include <queue>
34
35 namespace Dali
36 {
37 namespace Internal
38 {
39 namespace Adaptor
40 {
41 struct Clipboard::Impl
42 {
43   Impl(Ecore_X_Window ecoreXwin)
44   {
45     mApplicationWindow = ecoreXwin;
46   }
47
48   bool HasType(const std::string& mimeType)
49   {
50     for(const auto& type : mMimeTypes)
51     {
52       if(type == mimeType)
53       {
54         return true;
55       }
56     }
57     return false;
58   }
59
60   void UpdateData(std::string& mimeType, std::string& data, bool clearBuffer)
61   {
62     if(clearBuffer)
63     {
64       mMimeTypes.clear();
65       mDatas.clear();
66     }
67     mMimeTypes.push_back(mimeType);
68     mDatas[mimeType] = data;
69   }
70
71   bool SetData(const Dali::Clipboard::ClipData& clipData)
72   {
73     std::string mimeType = clipData.GetMimeType();
74     std::string data     = clipData.GetData();
75
76     if(mimeType.empty() || data.empty())
77     {
78       return false;
79     }
80
81     if(mLastType != mimeType && !mMultiSelectionTimeout)
82     {
83       bool clearBuffer = HasType(mimeType);
84       UpdateData(mimeType, data, clearBuffer);
85     }
86     else
87     {
88       UpdateData(mimeType, data, true);
89     }
90
91     mLastType = mimeType;
92
93     mDataSentSignal.Emit(mimeType.c_str(), data.c_str());
94     mDataSelectedSignal.Emit(mimeType.c_str());
95
96     SetMultiSelectionTimeout();
97
98     return true;
99   }
100
101   uint32_t GetData(const std::string& mimeType)
102   {
103     if(mDatas.count(mimeType))
104     {
105       mDataId++;
106       mDataReceiveQueue.push(std::make_pair(mDataId, mimeType));
107
108       // For consistency of operation with tizen Wl2, a fake callback is occurs using a timer.
109       if(mDataReceiveTimer.IsRunning())
110       {
111         mDataReceiveTimer.Stop();
112       }
113       mDataReceiveTimer.Start();
114       DALI_LOG_RELEASE_INFO("request data, id:%u, request type:%s\n", mDataId, mimeType.c_str());
115       return mDataId;
116     }
117     return 0u;
118   }
119
120   bool OnReceiveData()
121   {
122     while(!mDataReceiveQueue.empty())
123     {
124       auto item = mDataReceiveQueue.front();
125       mDataReceiveQueue.pop();
126
127       uint32_t    requestId   = item.first;
128       std::string requestType = item.second;
129       std::string data        = "";
130
131       if(mDatas.count(requestType))
132       {
133         data = mDatas[requestType];
134       }
135
136       DALI_LOG_RELEASE_INFO("receive data, success signal emit, id:%u, type:%s, data:%s\n", requestId, requestType.c_str(), data.c_str());
137       mDataReceivedSignal.Emit(requestId, requestType.c_str(), data.c_str());
138     }
139     return false;
140   }
141
142   void SetMultiSelectionTimeout()
143   {
144     mMultiSelectionTimeout = false;
145     if(mMultiSelectionTimeoutTimer.IsRunning())
146     {
147       mMultiSelectionTimeoutTimer.Stop();
148     }
149     mMultiSelectionTimeoutTimer.Start();
150   }
151
152   bool OnMultiSelectionTimeout()
153   {
154     mMultiSelectionTimeout = true;
155     return false;
156   }
157
158   Ecore_X_Window mApplicationWindow{};
159   uint32_t       mDataId{0};
160   std::string    mLastType{};
161
162   std::vector<std::string>                     mMimeTypes{};
163   std::map<std::string, std::string>           mDatas{};            // type, data
164   std::queue<std::pair<uint32_t, std::string>> mDataReceiveQueue{}; // id, type
165
166   Dali::Clipboard::DataSentSignalType     mDataSentSignal{};
167   Dali::Clipboard::DataReceivedSignalType mDataReceivedSignal{};
168   Dali::Clipboard::DataSelectedSignalType mDataSelectedSignal{};
169
170   Dali::Timer mDataReceiveTimer{};
171   Dali::Timer mMultiSelectionTimeoutTimer{};
172   bool        mMultiSelectionTimeout{false};
173 };
174
175 Clipboard::Clipboard(Impl* impl)
176 : mImpl(impl)
177 {
178   mImpl->mDataReceiveTimer = Dali::Timer::New(10u);
179   mImpl->mDataReceiveTimer.TickSignal().Connect(this, &Clipboard::OnReceiveData);
180
181   mImpl->mMultiSelectionTimeoutTimer = Dali::Timer::New(500u);
182   mImpl->mMultiSelectionTimeoutTimer.TickSignal().Connect(this, &Clipboard::OnMultiSelectionTimeout);
183 }
184
185 Clipboard::~Clipboard()
186 {
187   delete mImpl;
188 }
189
190 Dali::Clipboard Clipboard::Get()
191 {
192   Dali::Clipboard clipboard;
193
194   Dali::SingletonService service(SingletonService::Get());
195   if(service)
196   {
197     // Check whether the singleton is already created
198     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
199     if(handle)
200     {
201       // If so, downcast the handle
202       clipboard = Dali::Clipboard(dynamic_cast<Clipboard*>(handle.GetObjectPtr()));
203     }
204     else
205     {
206       Adaptor& adaptorImpl(Adaptor::GetImplementation(Adaptor::Get()));
207       Any      nativewindow = adaptorImpl.GetNativeWindowHandle();
208
209       // The Ecore_X_Window needs to use the Clipboard.
210       // Only when the render surface is window, we can get the Ecore_X_Window.
211       Ecore_X_Window ecoreXwin(AnyCast<Ecore_X_Window>(nativewindow));
212       if(ecoreXwin)
213       {
214         // If we fail to get Ecore_X_Window, we can't use the Clipboard correctly.
215         // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
216         // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
217         Clipboard::Impl* impl(new Clipboard::Impl(ecoreXwin));
218         clipboard = Dali::Clipboard(new Clipboard(impl));
219         service.Register(typeid(clipboard), clipboard);
220       }
221     }
222   }
223
224   return clipboard;
225 }
226
227 bool Clipboard::IsAvailable()
228 {
229   Dali::SingletonService service(SingletonService::Get());
230   if(service)
231   {
232     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
233     if(handle)
234     {
235       return true;
236     }
237   }
238   return false;
239 }
240
241 Dali::Clipboard::DataSentSignalType& Clipboard::DataSentSignal()
242 {
243   return mImpl->mDataSentSignal;
244 }
245
246 Dali::Clipboard::DataReceivedSignalType& Clipboard::DataReceivedSignal()
247 {
248   return mImpl->mDataReceivedSignal;
249 }
250
251 Dali::Clipboard::DataSelectedSignalType& Clipboard::DataSelectedSignal()
252 {
253   return mImpl->mDataSelectedSignal;
254 }
255
256 bool Clipboard::HasType(const std::string& mimeType)
257 {
258   return mImpl->HasType(mimeType);
259 }
260
261 bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
262 {
263   return mImpl->SetData(clipData);
264 }
265
266 uint32_t Clipboard::GetData(const std::string& mimeType)
267 {
268   return mImpl->GetData(mimeType);
269 }
270
271 size_t Clipboard::NumberOfItems()
272 {
273   bool isItem = HasType(MIME_TYPE_TEXT_PLAIN) || HasType(MIME_TYPE_HTML) || HasType(MIME_TYPE_TEXT_URI);
274   return isItem ? 1u : 0u;
275 }
276
277 void Clipboard::ShowClipboard()
278 {
279 }
280
281 void Clipboard::HideClipboard(bool skipFirstHide)
282 {
283 }
284
285 bool Clipboard::IsVisible() const
286 {
287   return false;
288 }
289
290 bool Clipboard::OnReceiveData()
291 {
292   return mImpl->OnReceiveData();
293 }
294
295 bool Clipboard::OnMultiSelectionTimeout()
296 {
297   return mImpl->OnMultiSelectionTimeout();
298 }
299
300 } // namespace Adaptor
301
302 } // namespace Internal
303
304 } // namespace Dali