807f9db5df8b8b25cae70f87f8bcbf3fa05fd32f
[platform/core/uifw/dali-adaptor.git] / dali / internal / clipboard / ubuntu-x11 / clipboard-impl-x.cpp
1 /*
2  * Copyright (c) 2023 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/object/any.h>
25 #include <dali/public-api/object/type-registry.h>
26
27 // INTERNAL INCLUDES
28 #include <dali/devel-api/common/singleton-service.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30 #include <dali/internal/clipboard/common/clipboard-event-notifier-impl.h>
31 #include <dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h>
32
33 namespace //unnamed namespace
34 {
35 const char* const CBHM_WINDOW = "CBHM_XWIN";
36 const char* const CBHM_MSG    = "CBHM_MSG";
37 const char* const CBHM_ITEM   = "CBHM_ITEM";
38 const char* const CBHM_cCOUNT = "CBHM_cCOUNT";
39 const char* const CBHM_ERROR  = "CBHM_ERROR";
40 const char* const SET_ITEM    = "SET_ITEM";
41 const char* const SHOW        = "show0";
42 const char* const HIDE        = "cbhm_hide";
43 } // namespace
44
45 ///////////////////////////////////////////////////////////////////////////////////////////////////
46 // Clipboard
47 ///////////////////////////////////////////////////////////////////////////////////////////////////
48
49 namespace Dali
50 {
51 namespace Internal
52 {
53 namespace Adaptor
54 {
55 struct Clipboard::Impl
56 {
57   Impl(Ecore_X_Window ecoreXwin)
58   {
59     mApplicationWindow = ecoreXwin;
60   }
61
62   Ecore_X_Window mApplicationWindow;
63 };
64
65 Clipboard::Clipboard(Impl* impl)
66 : mImpl(impl)
67 {
68 }
69
70 Clipboard::~Clipboard()
71 {
72   delete mImpl;
73 }
74
75 Dali::Clipboard Clipboard::Get()
76 {
77   Dali::Clipboard clipboard;
78
79   Dali::SingletonService service(SingletonService::Get());
80   if(service)
81   {
82     // Check whether the singleton is already created
83     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
84     if(handle)
85     {
86       // If so, downcast the handle
87       clipboard = Dali::Clipboard(dynamic_cast<Clipboard*>(handle.GetObjectPtr()));
88     }
89     else
90     {
91       Adaptor& adaptorImpl(Adaptor::GetImplementation(Adaptor::Get()));
92       Any      nativewindow = adaptorImpl.GetNativeWindowHandle();
93
94       // The Ecore_X_Window needs to use the Clipboard.
95       // Only when the render surface is window, we can get the Ecore_X_Window.
96       Ecore_X_Window ecoreXwin(AnyCast<Ecore_X_Window>(nativewindow));
97       if(ecoreXwin)
98       {
99         // If we fail to get Ecore_X_Window, we can't use the Clipboard correctly.
100         // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
101         // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
102         Clipboard::Impl* impl(new Clipboard::Impl(ecoreXwin));
103         clipboard = Dali::Clipboard(new Clipboard(impl));
104         service.Register(typeid(clipboard), clipboard);
105       }
106     }
107   }
108
109   return clipboard;
110 }
111
112 bool Clipboard::IsAvailable()
113 {
114   Dali::SingletonService service(SingletonService::Get());
115   if(service)
116   {
117     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
118     if(handle)
119     {
120       return true;
121     }
122   }
123   return false;
124 }
125
126 bool Clipboard::SetItem(const std::string& itemData)
127 {
128   Ecore_X_Window cbhmWin      = ECore::WindowInterface::GetWindow();
129   Ecore_X_Atom   atomCbhmItem = ecore_x_atom_get(CBHM_ITEM);
130   Ecore_X_Atom   dataType     = ECORE_X_ATOM_STRING;
131
132   // Set item (property) to send
133   ecore_x_window_prop_property_set(cbhmWin, atomCbhmItem, dataType, 8, const_cast<char*>(itemData.c_str()), itemData.length() + 1);
134   ecore_x_sync();
135
136   // Trigger sending of item (property)
137   Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get(CBHM_MSG);
138   ECore::WindowInterface::SendXEvent(ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, SET_ITEM);
139   return true;
140 }
141
142 /*
143  * Request clipboard service to retrieve an item
144  */
145 void Clipboard::RequestItem()
146 {
147   int  index = 0;
148   char sendBuf[20];
149   snprintf(sendBuf, 20, "%s%d", CBHM_ITEM, index);
150   Ecore_X_Atom xAtomCbhmItem = ecore_x_atom_get(sendBuf);
151   Ecore_X_Atom xAtomItemType = 0;
152
153   std::string clipboardString(ECore::WindowInterface::GetWindowProperty(xAtomCbhmItem, &xAtomItemType, index));
154
155   // Only return the text string if the Atom type is text (Do not return a text string/URL for images).
156   if(!clipboardString.empty() &&
157      (xAtomItemType == ECORE_X_ATOM_TEXT || xAtomItemType == ECORE_X_ATOM_COMPOUND_TEXT || xAtomItemType == ECORE_X_ATOM_STRING || xAtomItemType == ECORE_X_ATOM_UTF8_STRING))
158   {
159     Ecore_X_Atom xAtomCbhmError = ecore_x_atom_get(CBHM_ERROR);
160     if(xAtomItemType != xAtomCbhmError)
161     {
162       // Call ClipboardEventNotifier to notify event observe of retrieved string
163       Dali::ClipboardEventNotifier clipboardEventNotifier(ClipboardEventNotifier::Get());
164       if(clipboardEventNotifier)
165       {
166         ClipboardEventNotifier& notifierImpl(ClipboardEventNotifier::GetImplementation(clipboardEventNotifier));
167
168         notifierImpl.SetContent(clipboardString);
169         notifierImpl.EmitContentSelectedSignal();
170       }
171     }
172   }
173 }
174
175 /*
176  * Get number of items in clipboard
177  */
178 unsigned int Clipboard::NumberOfItems()
179 {
180   Ecore_X_Atom xAtomCbhmCountGet = ecore_x_atom_get(CBHM_cCOUNT);
181
182   std::string ret(ECore::WindowInterface::GetWindowProperty(xAtomCbhmCountGet, NULL, 0));
183   int         count = 0;
184
185   if(!ret.empty())
186   {
187     count = atoi(ret.c_str());
188   }
189
190   return count;
191 }
192
193 /**
194  * Show clipboard window
195  * Function to send message to show the Clipboard (cbhm) as no direct API available
196  * Reference elementary/src/modules/ctxpopup_copypasteUI/cbhm_helper.c
197  */
198 void Clipboard::ShowClipboard()
199 {
200   // Claim the ownership of the SECONDARY selection.
201   ecore_x_selection_secondary_set(mImpl->mApplicationWindow, "", 1);
202   Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
203
204   // Launch the clipboard window
205   Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get(CBHM_MSG);
206   ECore::WindowInterface::SendXEvent(ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, SHOW);
207 }
208
209 void Clipboard::HideClipboard(bool skipFirstHide)
210 {
211   Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
212   // Launch the clipboard window
213   Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get(CBHM_MSG);
214   ECore::WindowInterface::SendXEvent(ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, HIDE);
215
216   // release the ownership of SECONDARY selection
217   ecore_x_selection_secondary_clear();
218 }
219
220 bool Clipboard::IsVisible() const
221 {
222   return false;
223 }
224
225 void Clipboard::ExcuteSend(void* event)
226 {
227 }
228
229 void Clipboard::ExcuteReceive(void* event, char*& data, int& length)
230 {
231   // Receive
232   Ecore_X_Event_Selection_Notify* selectionNotifyEvent = static_cast<Ecore_X_Event_Selection_Notify*>(event);
233
234   Ecore_X_Selection_Data* selectionData = static_cast<Ecore_X_Selection_Data*>(selectionNotifyEvent->data);
235   if(selectionData->data)
236   {
237     if(selectionNotifyEvent->selection == ECORE_X_SELECTION_SECONDARY)
238     {
239       // Claim the ownership of the SECONDARY selection.
240       ecore_x_selection_secondary_set(mImpl->mApplicationWindow, "", 1);
241       data = reinterpret_cast<char*>(selectionData->data);
242       length = selectionData->length;
243     }
244   }
245 }
246
247 } // namespace Adaptor
248
249 } // namespace Internal
250
251 } // namespace Dali