Fixed syns issue after render
[framework/osp/shell.git] / src / FShell_AppWidgetLayer.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Flora License, Version 1.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://floralicense.org/license/
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 /**
18  * @file                FShell_AppWidgetLayer.cpp
19  * @brief               This is the implementation file for the _AppWidgetLayer class.
20  */
21
22 #include <new>
23 #include <errno.h>\r
24 #include <string.h>
25 #include <sys/shm.h>
26 #include <X11/Xlib.h>
27 #include <X11/extensions/XShm.h>
28 #include <X11/Xutil.h>
29 #include <Evas.h>
30 #include <Ecore_X.h>
31 #include <provider.h>
32 #include <provider_buffer.h>
33 #include <FBaseSysLog.h>
34 #include <FBase_StringConverter.h>
35 #include <FGrpRectangle.h>
36 #include "FUi_Window.h"
37 #include "FShell_AppWidgetLayer.h"
38 #include "FShell_AppWidgetProviderManagerImpl.h"
39
40 //#define _BUFFER_TEST
41
42 using namespace std;
43 using namespace Tizen::Base;
44 using namespace Tizen::Graphics;
45 using namespace Tizen::Ui::Animations;
46 using namespace Tizen::Ui;
47 using namespace Tizen::Shell;
48
49 namespace
50 {
51
52 void*
53 AllocRenderBuffer(void* pData, int size)
54 {
55         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
56         SysTryReturn(NID_UI_CTRL, pAppWidgetLayer, null, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
57
58         return pAppWidgetLayer->AllocCanvas(size);
59 }
60
61 void
62 FreeRenderBuffer(void* pData, void* pCanvas)
63 {
64         SysTryReturnVoidResult(NID_UI_CTRL, pCanvas, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
65
66         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
67         SysTryReturnVoidResult(NID_UI_CTRL, pAppWidgetLayer, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
68
69         pAppWidgetLayer->FreeCanvas(pCanvas);
70 }
71
72 void
73 PostRender(void* pData, Evas* pEvas, void* pEventInfo)
74 {
75         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
76         SysTryReturnVoidResult(NID_UI_CTRL, pAppWidgetLayer, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
77
78         pAppWidgetLayer->OnRendered();
79 }
80
81 }
82
83 namespace Tizen { namespace Shell
84 {
85
86 _AppWidgetLayer::_AppWidgetLayer(const FloatDimension& size)
87         : __isReleased(false)
88         , __size(size)
89         , __pEcoreEvas(null)
90         , __pEvasObject(null)
91         , __providerId(L"")
92         , __pRenderBuffer(null)
93         , __bufferSize(0)
94         , __pixmapId(-1)
95 {
96 }
97
98 _AppWidgetLayer::~_AppWidgetLayer(void)
99 {
100         __pRenderBuffer = null;
101         __pixmapId = -1;
102 }
103
104 result
105 _AppWidgetLayer::OnConstructed(void)
106 {
107         result r = E_SUCCESS;
108
109         unique_ptr<Ecore_Evas, _EcoreEvasDeleter> pEcoreEvas(ecore_evas_buffer_allocfunc_new(__size.width, __size.height, AllocRenderBuffer, FreeRenderBuffer, this));
110         SysTryReturn(NID_UI_CTRL, pEcoreEvas, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
111
112         ecore_evas_alpha_set(pEcoreEvas.get(), EINA_TRUE);
113         ecore_evas_manual_render_set(pEcoreEvas.get(), EINA_FALSE);
114         ecore_evas_resize(pEcoreEvas.get(), __size.width, __size.height);
115         ecore_evas_activate(pEcoreEvas.get());
116
117         Evas* pEvas = ecore_evas_get(pEcoreEvas.get());
118         SysTryReturn(NID_UI_CTRL, pEvas, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
119
120         evas_event_callback_add(pEvas, EVAS_CALLBACK_RENDER_POST, PostRender, this);
121
122         unique_ptr<Evas_Object, _EvasObjectDeleter> pEvasObject(evas_object_rectangle_add(pEvas));
123         SysTryReturn(NID_UI_CTRL, pEvasObject, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
124
125         evas_object_resize(pEvasObject.get(), __size.width, __size.height);
126         evas_object_color_set(pEvasObject.get(), 0, 0, 0, 255);
127
128         r = Initialize(pEvasObject.get());
129         SysTryReturn(NID_UI_CTRL, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
130
131         __pEcoreEvas = move(pEcoreEvas);
132         __pEvasObject = move(pEvasObject);
133
134         ecore_evas_alpha_set(__pEcoreEvas.get(), EINA_TRUE);
135         evas_object_color_set(__pEvasObject.get(), 0, 0, 0, 0);
136
137         return r;
138 }
139
140 result
141 _AppWidgetLayer::SetProviderId(const String& providerId)
142 {
143         __providerId = providerId;
144
145         __pixmapId = AcquirePixmap();
146         SysTryReturn(NID_UI_CTRL, __pixmapId != -1, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
147
148         SysLog(NID_UI_CTRL, "pixmapId (%d)", __pixmapId);
149
150         result r = RegisterTouchEventListener();
151         SysTryReturn(NID_UI_CTRL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
152
153         return r;
154 }
155
156 String
157 _AppWidgetLayer::GetProviderId(void) const
158 {
159         return __providerId;
160 }
161
162 int
163 _AppWidgetLayer::GetPixmapId(void) const
164 {
165         return __pixmapId;
166 }
167
168 void
169 _AppWidgetLayer::SetLayerBounds(const FloatRectangle& bounds)
170 {
171         __size = FloatDimension(bounds.width, bounds.height);
172
173         ecore_evas_resize(__pEcoreEvas.get(), __size.width, __size.height);
174
175 //      FloatRectangle fBounds(static_cast<float>(bounds.x), static_cast<float>(bounds.y), static_cast<float>(bounds.width), static_cast<float>(bounds.height));
176         SetBounds(bounds);
177 }
178
179 void*
180 _AppWidgetLayer::AllocCanvas(int size)
181 {
182         SysTryReturn(NID_UI_CTRL, size > 0, null, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
183
184         __bufferSize = size;
185         void* pBuffer =  malloc(__bufferSize);
186         SysTryReturn(NID_UI_CTRL, pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
187
188         __pRenderBuffer = pBuffer;
189
190         SysLog(NID_UI_CTRL, "buffer (0x%x) size (%d)", pBuffer, __bufferSize);
191
192         __isReleased = false;
193
194         return __pRenderBuffer;
195 }
196
197 void
198 _AppWidgetLayer::FreeCanvas(void* pCanvas)
199 {
200         if (!__isReleased)
201         {
202                 ReleasePixmap();
203                 __isReleased = true;
204         }
205
206         if (pCanvas)
207         {
208                 free(pCanvas);
209         }
210
211         __pixmapId = -1;
212         __pRenderBuffer = null;
213 }
214
215 result
216 _AppWidgetLayer::SyncPixmap(const FloatDimension& size)
217 {
218         SysTryReturn(NID_UI_CTRL, __pRenderBuffer, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
219
220         SysLog(NID_UI_CTRL, "buffer (0x%x) size (%d) pixmapId (%d) width(%f) height(%f)", __pRenderBuffer, __bufferSize, __pixmapId, size.width, size.height);
221
222         Display* pDisplay = static_cast<Display*>(ecore_x_display_get());
223         SysTryReturn(NID_UI_CTRL, pDisplay, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
224
225         result r = E_SUCCESS;
226         XShmSegmentInfo xShmSegmentInfo;
227         XImage* pXImage = null;
228         GC gc;
229         Screen* pScreen = null;
230         Visual* pVisual = null;
231
232         xShmSegmentInfo.shmid = shmget(IPC_PRIVATE, __bufferSize, IPC_CREAT | 0666);
233         SysTryReturn(NID_UI_CTRL,  xShmSegmentInfo.shmid >= 0, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
234
235         xShmSegmentInfo.readOnly = False;
236         xShmSegmentInfo.shmaddr = static_cast<char*>(shmat(xShmSegmentInfo.shmid, null, 0));
237         SysTryCatch(NID_UI_CTRL, xShmSegmentInfo.shmaddr != (void *)-1, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
238
239         pScreen = DefaultScreenOfDisplay(pDisplay);
240         SysTryCatch(NID_UI_CTRL, pScreen, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
241
242         pVisual = DefaultVisualOfScreen(pScreen);
243         SysTryCatch(NID_UI_CTRL, pVisual, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
244
245         pXImage = XShmCreateImage(pDisplay, pVisual, 32, ZPixmap, null, &xShmSegmentInfo, size.width, size.height);
246         SysTryCatch(NID_UI_CTRL, pXImage, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
247
248         pXImage->data = xShmSegmentInfo.shmaddr;
249         XShmAttach(pDisplay, &xShmSegmentInfo);
250         XSync(pDisplay, False);
251
252         gc = XCreateGC(pDisplay, static_cast<Pixmap>(__pixmapId), 0, null);
253         SysTryCatch(NID_UI_CTRL, gc, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
254
255         memcpy(pXImage->data, __pRenderBuffer, __bufferSize);
256
257 #if defined(_BUFFER_TEST)
258         {
259                 FILE* pFile = null;\r
260                 static int idx = 0;\r
261                 char filename[1024];\r
262                 snprintf(filename, sizeof(filename), "/opt/out%d.raw", idx++);\r
263                 pFile = fopen(filename, "w+b");\r
264                 if (pFile)\r
265                 {\r
266                         fwrite(__pRenderBuffer, __bufferSize, 1, pFile);\r
267                         fclose(pFile);\r
268                         SysLog(NID_UI_CTRL, "_BUFFER_TEST: buffer (0x%x) size (%d) pixmapId (%d) width(%f) height(%f)", __pRenderBuffer, __bufferSize, __pixmapId, size.width, size.height);\r
269                 }\r
270                 else\r
271                 {\r
272                         SysLog(NID_UI_CTRL, "File open failed: (%s) buffer (0x%x) size (%d) pixmapId (%d)", strerror(errno), __pRenderBuffer, __bufferSize, __pixmapId);\r
273                 }\r
274         }
275 #endif // _BUFFER_TEST
276
277         // Do not send the event. Instead of X event, master will send the updated event to the viewer
278         XShmPutImage(pDisplay, static_cast<Pixmap>(__pixmapId), gc, pXImage, 0, 0, 0, 0, size.width, size.height, False);
279         XSync(pDisplay, False);
280
281         XFreeGC(pDisplay, gc);
282         XShmDetach(pDisplay, &xShmSegmentInfo);
283         XDestroyImage(pXImage);
284
285         if (xShmSegmentInfo.shmaddr != (void *)-1)
286         {
287                 shmdt(xShmSegmentInfo.shmaddr);
288         }
289
290         if (xShmSegmentInfo.shmid >= 0)
291         {
292                 shmctl(xShmSegmentInfo.shmid, IPC_RMID, 0);
293         }
294
295         return r;
296
297 CATCH:
298
299         if (pDisplay)
300         {
301                 XShmDetach(pDisplay, &xShmSegmentInfo);
302         }
303
304         if (pXImage)
305         {
306                 XDestroyImage(pXImage);
307         }
308
309         if (xShmSegmentInfo.shmaddr != (void *)-1)
310         {
311                 shmdt(xShmSegmentInfo.shmaddr);
312         }
313
314         if (xShmSegmentInfo.shmid >= 0)
315         {
316                 shmctl(xShmSegmentInfo.shmid, IPC_RMID, 0);
317         }
318
319         return E_OUT_OF_MEMORY;
320 }
321
322 void
323 _AppWidgetLayer::OnRendered(void)
324 {
325         if (__pixmapId == -1)
326         {
327                 __pixmapId = AcquirePixmap();
328                 SysTryReturnVoidResult(NID_UI_CTRL, __pixmapId >= 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
329         }
330
331         result r = SyncPixmap(__size);
332         SysTryReturnVoidResult(NID_UI_CTRL, r == E_SUCCESS, r, "[%s] Propagating.", GetErrorMessage(r));
333
334         r = Sync(__size);
335         SysTryReturnVoidResult(NID_UI_CTRL, r == E_SUCCESS, r, "[%s] Propagating.", GetErrorMessage(r));
336 }
337
338 result
339 _AppWidgetLayer::RegisterTouchEventListener(void)
340 {
341         result r = _AppWidgetProviderManagerImpl::GetInstance()->SetAppWidgetTouchEventListener(__providerId, *this);
342         SysTryReturn(NID_UI_CTRL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
343
344         return r;
345 }
346
347 int
348 _AppWidgetLayer::AcquirePixmap(void)
349 {
350         SysTryReturn(NID_UI_CTRL, !__providerId.IsEmpty(), -1, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
351
352         int pixmapId = -1;
353
354         result r = _AppWidgetProviderManagerImpl::GetInstance()->RequestSharedMemoryId(__providerId, __size.width, __size.height, pixmapId);
355         SysTryReturn(NID_UI_CTRL, r == E_SUCCESS, -1, r, "[%s] Propagating.", GetErrorMessage(r));
356
357         SysLog(NID_UI_CTRL, "pixmapId(%d) size(%f %f)", pixmapId, __size.width, __size.height);
358
359         return pixmapId;
360 }
361
362 result
363 _AppWidgetLayer::Sync(const FloatDimension& size)
364 {
365         SysTryReturn(NID_UI_CTRL, !__providerId.IsEmpty(), E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
366
367         result r = _AppWidgetProviderManagerImpl::GetInstance()->RequestSyncSharedMemory(__providerId, size.width, size.height);
368         SysTryReturn(NID_UI_CTRL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
369
370         return r;
371 }
372
373 void
374 _AppWidgetLayer::ReleasePixmap(void)
375 {
376         SysTryReturnVoidResult(NID_UI_CTRL, !__providerId.IsEmpty(), E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
377
378         _AppWidgetProviderManagerImpl::GetInstance()->RequestReleaseSharedMemory(__providerId);
379 }
380
381 int
382 _AppWidgetLayer::OnTouchEventRecevied(int eventType, double timestamp, double x, double y)
383 {
384         SysLog(NID_UI_CTRL, "eventType (%d) timestamp (%f) (%f, %f)", eventType, timestamp, x, y);
385
386         int xPos = __size.width * x;
387         int yPos = __size.height * y;
388
389         Evas* pEvas = ecore_evas_get(__pEcoreEvas.get());
390         SysTryReturn(NID_UI_CTRL, pEvas, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
391
392         switch (eventType)
393         {
394         case BUFFER_EVENT_ENTER:
395                 evas_event_feed_mouse_in(pEvas, timestamp, null);
396                 break;
397
398         case BUFFER_EVENT_LEAVE:
399                 evas_event_feed_mouse_out(pEvas, timestamp, null);
400                 break;
401
402         case BUFFER_EVENT_DOWN:
403                 evas_event_feed_mouse_in(pEvas, timestamp, null);
404                 evas_event_feed_mouse_move(pEvas, xPos, yPos, timestamp + 0.01f, null);
405                 evas_event_feed_mouse_down(pEvas, 1, EVAS_BUTTON_NONE, timestamp + 0.02f, null);
406                 break;
407
408         case BUFFER_EVENT_MOVE:
409                 evas_event_feed_mouse_move(pEvas, xPos, yPos, timestamp, null);
410                 break;
411
412         case BUFFER_EVENT_UP:
413                 evas_event_feed_mouse_up(pEvas, 1, EVAS_BUTTON_NONE, timestamp, null);
414                 evas_event_feed_mouse_out(pEvas, timestamp + 0.01f, null);
415                 break;
416
417         default:
418                 break;
419         }
420
421         return 0;
422 }
423
424
425 }} // Tizen::Shell