feb08a5195409efe782102985f77fc9cb0b4dd5a
[framework/osp/shell.git] / src / FShell_AppWidgetLayer.cpp
1 //
2 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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  * @file                FShell_AppWidgetLayer.cpp
18  * @brief               This is the implementation file for the _AppWidgetLayer class.
19  */
20
21 #include <new>
22 #include <errno.h>
23 #include <string.h>
24 #include <sys/shm.h>
25 #include <X11/Xlib.h>
26 #include <X11/extensions/XShm.h>
27 #include <X11/Xutil.h>
28 #include <Evas.h>
29 #include <Ecore_X.h>
30 #include <provider.h>
31 #include <provider_buffer.h>
32 #include <FBaseSysLog.h>
33 #include <FBase_StringConverter.h>
34 #include <FGrpRectangle.h>
35 #include "FUi_Window.h"
36 #include "FShell_AppWidgetBuffer.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_SHELL, 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_SHELL, pCanvas, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
65
66         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
67         SysTryReturnVoidResult(NID_SHELL, pAppWidgetLayer, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
68
69         pAppWidgetLayer->FreeCanvas(pCanvas);
70 }
71
72 void
73 PreRender(void* pData, Evas* pEvas, void* pEventInfo)
74 {
75         SysLog(NID_SHELL, "ENTER");
76
77         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
78         SysTryReturnVoidResult(NID_SHELL, pAppWidgetLayer, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
79
80         pAppWidgetLayer->OnNativeCanvasPreRendered();
81 }
82
83 void
84 PostRender(void* pData, Evas* pEvas, void* pEventInfo)
85 {
86         SysLog(NID_SHELL, "ENTER");
87
88         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
89         SysTryReturnVoidResult(NID_SHELL, pAppWidgetLayer, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
90
91         pAppWidgetLayer->OnNativeCanvasPostRendered();
92 }
93
94 }
95
96 namespace Tizen { namespace Shell
97 {
98
99 _AppWidgetLayer::_AppWidgetLayer(const Tizen::Base::String& providerId, const FloatDimension& size)
100         : __isReleased(false)
101         , __size(size)
102         , __pEcoreEvas(null)
103         , __pEvasObject(null)
104         , __providerId(providerId)
105         , __pRenderBuffer(null)
106         , __pTempBuffer(null)
107         , __bufferSize(0)
108         , __pixmapId(-1)
109         , __pAppWidgetBuffer(new (std::nothrow) _AppWidgetBuffer)
110 {
111 }
112
113 _AppWidgetLayer::~_AppWidgetLayer(void)
114 {
115         __pRenderBuffer = null;
116         __pTempBuffer = null;
117         __pixmapId = -1;
118 }
119
120 result
121 _AppWidgetLayer::OnConstructed(void)
122 {
123         result r = E_SUCCESS;
124
125         __pAppWidgetBuffer->Initialize();
126
127         unique_ptr<Ecore_Evas, _EcoreEvasDeleter> pEcoreEvas(ecore_evas_buffer_allocfunc_new(__size.width, __size.height, AllocRenderBuffer, FreeRenderBuffer, this));
128         SysTryReturn(NID_SHELL, pEcoreEvas, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
129
130         ecore_evas_alpha_set(pEcoreEvas.get(), EINA_TRUE);
131         ecore_evas_manual_render_set(pEcoreEvas.get(), EINA_FALSE);
132         ecore_evas_resize(pEcoreEvas.get(), __size.width, __size.height);
133         ecore_evas_activate(pEcoreEvas.get());
134
135         Evas* pEvas = ecore_evas_get(pEcoreEvas.get());
136         SysTryReturn(NID_SHELL, pEvas, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
137
138         evas_event_callback_add(pEvas, EVAS_CALLBACK_RENDER_PRE, PreRender, this);
139 //      evas_event_callback_add(pEvas, EVAS_CALLBACK_RENDER_POST, PostRender, this);
140
141         unique_ptr<Evas_Object, _EvasObjectDeleter> pEvasObject(evas_object_rectangle_add(pEvas));
142         SysTryReturn(NID_SHELL, pEvasObject, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
143
144         evas_object_resize(pEvasObject.get(), __size.width, __size.height);
145         evas_object_color_set(pEvasObject.get(), 0, 0, 0, 255);
146
147         r = Initialize(pEvasObject.get());
148         SysTryReturn(NID_SHELL, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
149
150         __pEcoreEvas = move(pEcoreEvas);
151         __pEvasObject = move(pEvasObject);
152
153         ecore_evas_alpha_set(__pEcoreEvas.get(), EINA_TRUE);
154         evas_object_color_set(__pEvasObject.get(), 0, 0, 0, 0);
155
156         if (!__providerId.IsEmpty())
157         {
158                 r = RegisterTouchEventListener();
159                 SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
160         }
161
162         return r;
163 }
164
165 result
166 _AppWidgetLayer::SetProviderId(const String& providerId)
167 {
168         __providerId = providerId;
169
170         result r = RegisterTouchEventListener();
171         SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
172
173         return r;
174 }
175
176 String
177 _AppWidgetLayer::GetProviderId(void) const
178 {
179         return __providerId;
180 }
181
182 int
183 _AppWidgetLayer::GetPixmapId(void) const
184 {
185         return __pixmapId;
186 }
187
188 void
189 _AppWidgetLayer::SetLayerBounds(const FloatRectangle& bounds)
190 {
191         __size = FloatDimension(bounds.width, bounds.height);
192
193         ecore_evas_resize(__pEcoreEvas.get(), __size.width, __size.height);
194
195         SetBounds(bounds);
196 }
197
198 void*
199 _AppWidgetLayer::AllocCanvas(int size)
200 {
201         SysTryReturn(NID_SHELL, size > 0, null, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
202
203         __bufferSize = size;
204         void* pBuffer = null;
205
206         if (__providerId.IsEmpty())
207         {
208                 __pTempBuffer =  malloc(__bufferSize);
209                 SysTryReturn(NID_SHELL, __pTempBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
210                 
211                 pBuffer = __pTempBuffer;
212         }
213         else
214         {
215                 if (__pixmapId == -1)
216                 {
217                         __pixmapId = AcquirePixmap();
218                         SysTryReturn(NID_SHELL, __pixmapId != -1, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
219                 }
220
221                 __pRenderBuffer = __pAppWidgetBuffer->AllocBuffer(__pixmapId, __size);
222                 pBuffer = __pRenderBuffer;
223                 __pAppWidgetBuffer->UnlockBuffer();
224         }
225
226         SysLog(NID_SHELL, "buffer (0x%x 0x%x) size (%d) pixmap (%d)", __pTempBuffer, __pRenderBuffer, __bufferSize, __pixmapId);
227
228         __isReleased = false;
229
230         return pBuffer;
231 }
232
233 void
234 _AppWidgetLayer::FreeCanvas(void* pCanvas)
235 {
236         SysLog(NID_SHELL, "buffer (0x%x 0x%x 0x%x) size (%d)", __pTempBuffer, __pRenderBuffer, pCanvas, __bufferSize);
237
238         if (__pTempBuffer)
239         {
240                 free(__pTempBuffer);
241                 __pTempBuffer = null;
242         }
243         else
244         {
245                 if (__pAppWidgetBuffer)
246                 {
247                         __pAppWidgetBuffer->DeallocBuffer();
248                 }
249         }
250
251         if (!__isReleased)
252         {
253                 ReleasePixmap();
254                 __isReleased = true;
255         }
256
257         __pixmapId = -1;
258         __pRenderBuffer = null;
259 }
260
261 result
262 _AppWidgetLayer::SyncPixmap(const FloatDimension& size)
263 {
264         SysTryReturn(NID_SHELL, __pRenderBuffer, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
265         SysTryReturn(NID_SHELL, __pAppWidgetBuffer, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
266
267         SysLog(NID_SHELL, "buffer (0x%x) size (%d) pixmapId (%d) width(%f) height(%f)", __pRenderBuffer, __bufferSize, __pixmapId, size.width, size.height);
268
269         XShmPutImage(__pAppWidgetBuffer->GetDisplay(), static_cast<Pixmap>(__pixmapId), __pAppWidgetBuffer->GetGc(), __pAppWidgetBuffer->GetXImage(), 0, 0, 0, 0, size.width, size.height, False);
270         XSync(__pAppWidgetBuffer->GetDisplay(), False);
271
272         return E_SUCCESS;
273 }
274
275 void
276 _AppWidgetLayer::OnRendered(void)
277 {
278         result r = E_SUCCESS;
279
280         if (!__pAppWidgetBuffer->IsGemBufferEnabled())
281         {
282                 if (__pixmapId == -1)
283                 {
284                         __pixmapId = AcquirePixmap();
285                         SysTryReturnVoidResult(NID_SHELL, __pixmapId >= 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
286                 }
287
288                 r = SyncPixmap(__size);
289                 SysTryReturnVoidResult(NID_SHELL, r == E_SUCCESS, r, "[%s] Propagating.", GetErrorMessage(r));
290         }
291
292         SysLog(NID_SHELL, "ENTER");
293
294         r = Sync(__size);
295         SysTryReturnVoidResult(NID_SHELL, r == E_SUCCESS, r, "[%s] Propagating.", GetErrorMessage(r));
296 }
297
298 void
299 _AppWidgetLayer::OnNativeCanvasPreRendered(void)
300 {
301         SysLog(NID_SHELL, "ENTER");
302
303         __pAppWidgetBuffer->LockBuffer();
304 }
305
306 void
307 _AppWidgetLayer::OnNativeCanvasPostRendered(void)
308 {
309 }
310
311 result
312 _AppWidgetLayer::RegisterTouchEventListener(void)
313 {
314         result r = _AppWidgetProviderManagerImpl::GetInstance()->SetAppWidgetTouchEventListener(__providerId, *this);
315         SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
316
317         return r;
318 }
319
320 int
321 _AppWidgetLayer::AcquirePixmap(void)
322 {
323         SysTryReturn(NID_SHELL, !__providerId.IsEmpty(), -1, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
324
325         int pixmapId = -1;
326
327         result r = _AppWidgetProviderManagerImpl::GetInstance()->RequestSharedMemoryId(__providerId, __size.width, __size.height, pixmapId);
328         SysTryReturn(NID_SHELL, r == E_SUCCESS, -1, r, "[%s] Propagating.", GetErrorMessage(r));
329
330         SysLog(NID_SHELL, "pixmapId(%d) size(%f %f)", pixmapId, __size.width, __size.height);
331
332         return pixmapId;
333 }
334
335 result
336 _AppWidgetLayer::Sync(const FloatDimension& size)
337 {
338         SysTryReturn(NID_SHELL, !__providerId.IsEmpty(), E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
339
340         result r = _AppWidgetProviderManagerImpl::GetInstance()->RequestSyncSharedMemory(__providerId, size.width, size.height);
341         SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
342
343         return r;
344 }
345
346 void
347 _AppWidgetLayer::ReleasePixmap(void)
348 {
349         SysTryReturnVoidResult(NID_SHELL, !__providerId.IsEmpty(), E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
350
351         _AppWidgetProviderManagerImpl::GetInstance()->RequestReleaseSharedMemory(__providerId);
352 }
353
354 int
355 _AppWidgetLayer::OnTouchEventRecevied(int eventType, double timestamp, double x, double y)
356 {
357         SysLog(NID_SHELL, "eventType (%d) timestamp (%f) (%f, %f)", eventType, timestamp, x, y);
358
359         int xPos = __size.width * x;
360         int yPos = __size.height * y;
361
362         Evas* pEvas = ecore_evas_get(__pEcoreEvas.get());
363         SysTryReturn(NID_SHELL, pEvas, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
364
365         switch (eventType)
366         {
367         case BUFFER_EVENT_ENTER:
368                 evas_event_feed_mouse_in(pEvas, timestamp, null);
369                 break;
370
371         case BUFFER_EVENT_LEAVE:
372                 evas_event_feed_mouse_out(pEvas, timestamp, null);
373                 break;
374
375         case BUFFER_EVENT_DOWN:
376                 evas_event_feed_mouse_in(pEvas, timestamp, null);
377                 evas_event_feed_mouse_move(pEvas, xPos, yPos, timestamp + 0.01f, null);
378                 evas_event_feed_mouse_down(pEvas, 1, EVAS_BUTTON_NONE, timestamp + 0.02f, null);
379                 break;
380
381         case BUFFER_EVENT_MOVE:
382                 evas_event_feed_mouse_move(pEvas, xPos, yPos, timestamp, null);
383                 break;
384
385         case BUFFER_EVENT_UP:
386                 evas_event_feed_mouse_up(pEvas, 1, EVAS_BUTTON_NONE, timestamp, null);
387                 evas_event_feed_mouse_out(pEvas, timestamp + 0.01f, null);
388                 break;
389
390         default:
391                 break;
392         }
393
394         return 0;
395 }
396
397 void
398 _AppWidgetLayer::Flush(void)
399 {
400         bool needed = IsFlushNeeded();
401
402         if (needed)
403         {
404                 Evas* pEvas = ecore_evas_get(__pEcoreEvas.get());
405                 SysTryReturnVoidResult(NID_SHELL, pEvas, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(E_OUT_OF_MEMORY));
406
407                 evas_damage_rectangle_add(pEvas, 0, 0, __size.width, __size.height);
408         }
409
410         _EflLayer::Flush();
411
412         if (needed)
413         {
414                 void* pBuffer = const_cast<void*>(ecore_evas_buffer_pixels_get(__pEcoreEvas.get()));
415                 SysTryReturnVoidResult(NID_SHELL, pBuffer, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(E_OUT_OF_MEMORY));
416
417                 evas_data_argb_unpremul(static_cast<unsigned int*>(pBuffer), __size.width * __size.height);
418
419                 OnRendered();
420         }
421
422         __pAppWidgetBuffer->UnlockBuffer();
423 }
424
425 }} // Tizen::Shell