877bf79ef972ae5a2e0301c0d3cad5090a39cf25
[platform/core/uifw/dali-adaptor.git] / adaptors / widget / internal / widget-impl.cpp
1 /*
2  * Copyright (c) 2014 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 "widget-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <aul.h>
23 #include <aul_app_com.h>
24 #include <appcore_multiwindow_base.h>
25 #include <unistd.h>
26 #include <screen_connector_provider.h>
27
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic ignored "-Wold-style-cast"
30 #include <glib.h>
31 #pragma GCC diagnostic pop
32
33 #include <system_info.h>
34 #include <string.h>
35
36 #include <dali/integration-api/debug.h>
37 #include <dali/public-api/math/vector2.h>
38
39 // INTERNAL INCLUDES
40 #include <widget-data.h>
41 #include <adaptor.h>
42
43 namespace Dali
44 {
45 namespace Internal
46 {
47
48 namespace Adaptor
49 {
50
51 namespace
52 {
53
54 static bool IsWidgetFeatureEnabled()
55 {
56   static bool feature = false;
57   static bool retrieved = false;
58   int ret;
59
60   if(retrieved == true)
61     return feature;
62
63   ret = system_info_get_platform_bool("http://tizen.org/feature/shell.appwidget", &feature);
64   if(ret != SYSTEM_INFO_ERROR_NONE)
65   {
66           DALI_LOG_ERROR("failed to get system info\n"); /* LCOV_EXCL_LINE */
67           return false; /* LCOV_EXCL_LINE */
68   }
69
70   retrieved = true;
71
72   return feature;
73 }
74
75 static int SendLifecycleEvent(const char* classId, const char* instanceId, int status)
76 {
77   bundle* bundleData = bundle_create();
78   int ret;
79
80   if (bundleData == NULL)
81   {
82     DALI_LOG_ERROR("out of memory");
83     return -1;
84   }
85
86   bundle_add_str(bundleData, AUL_K_WIDGET_ID, classId);
87   bundle_add_str(bundleData, AUL_K_WIDGET_INSTANCE_ID, instanceId);
88   bundle_add_byte(bundleData, AUL_K_WIDGET_STATUS, &status, sizeof(int));
89
90   char temp[256] = {0, };
91   char *packageId = NULL;
92   if(aul_app_get_pkgid_bypid(getpid(), temp, sizeof(temp)) == 0)
93   {
94     packageId = strdup(temp);
95   }
96
97   if(!packageId)
98   {
99     DALI_LOG_ERROR("package_id is NULL");
100     bundle_free(bundleData);
101     return -1;
102   }
103   bundle_add_str(bundleData, AUL_K_PKGID, packageId);
104
105   ret = aul_app_com_send("widget.status", bundleData);
106
107   if (ret < 0)
108     DALI_LOG_ERROR("send lifecycle error:%d\n", ret);
109
110   free(packageId);
111   bundle_free(bundleData);
112
113   return ret;
114 }
115
116 static int SendUpdateStatus(const char* classId, const char* instanceId, int status, bundle* extra )
117 {
118   bundle* bundleData;
119   int lifecycle = -1;
120   bundle_raw *raw = NULL;
121   int length;
122
123   bundleData = bundle_create();
124   if(!bundleData)
125   {
126     DALI_LOG_ERROR("out of memory");
127     return -1;
128   }
129
130   bundle_add_str(bundleData, AUL_K_WIDGET_ID, classId);
131   bundle_add_str(bundleData, AUL_K_WIDGET_INSTANCE_ID, instanceId);
132   bundle_add_byte(bundleData, AUL_K_WIDGET_STATUS, &status, sizeof(int));
133
134   if(extra)
135   {
136     bundle_encode(extra, &raw, &length);
137 #pragma GCC diagnostic push
138 #pragma GCC diagnostic ignored "-Wold-style-cast"
139     bundle_add_str(bundleData, "__WIDGET_CONTENT_INFO__", (const char*)raw);
140 #pragma GCC diagnostic pop
141     aul_widget_instance_add(classId, instanceId);
142   }
143
144   switch(status)
145   {
146     case AUL_WIDGET_INSTANCE_EVENT_CREATE:
147       lifecycle = Dali::Widget::WidgetLifecycleEventType::CREATE;
148       break;
149     case AUL_WIDGET_INSTANCE_EVENT_DESTROY:
150       lifecycle = Dali::Widget::WidgetLifecycleEventType::DESTROY;
151       break;
152     case AUL_WIDGET_INSTANCE_EVENT_PAUSE:
153       lifecycle = Dali::Widget::WidgetLifecycleEventType::PAUSE;
154       break;
155     case AUL_WIDGET_INSTANCE_EVENT_RESUME:
156       lifecycle = Dali::Widget::WidgetLifecycleEventType::RESUME;
157       break;
158   }
159
160   if (lifecycle > -1)
161     SendLifecycleEvent(classId, instanceId, lifecycle);
162
163   bundle_free(bundleData);
164
165   if (raw)
166     free(raw);
167
168   return 0;
169 }
170
171 } // anonymous namespace
172
173 Dali::Widget Widget::New( const std::string& id )
174 {
175   if(!IsWidgetFeatureEnabled())
176   {
177     DALI_LOG_ERROR("not supported");
178     Dali::Widget handle(NULL);
179     return handle;
180   }
181
182   if( id.size() < 1 )
183   {
184     DALI_LOG_ERROR("class id is NULL");
185     Dali::Widget handle(NULL);
186     return handle;
187   }
188
189   WidgetPtr widget ( new Widget( id ) );
190   Dali::Widget handle( widget.Get() );
191   return handle;
192 }
193
194 void Widget::InsertWidgetData( const char* id, Dali::WidgetData widgetData )
195 {
196   mIdWidgetContainer.push_back( std::make_pair( id, widgetData ) );
197 }
198
199 Dali::WidgetData* Widget::FindWidgetData( const char* key )
200 {
201   for( IdWidgetDataContainer::iterator iter = mIdWidgetContainer.begin(), endIter = mIdWidgetContainer.end(); iter != endIter; ++iter )
202   {
203     if( iter->first == key )
204     {
205       return &iter->second;
206     }
207   }
208   return NULL; // Not found
209 }
210
211 void Widget::DeleteWidgetData( const char* key )
212 {
213   for( IdWidgetDataContainer::iterator iter = mIdWidgetContainer.begin(), endIter = mIdWidgetContainer.end(); iter != endIter; ++iter )
214   {
215     if( iter->first == key )
216     {
217       iter = mIdWidgetContainer.erase(iter);
218       return;
219     }
220   }
221 }
222
223 static void OnInit(appcore_multiwindow_base_instance_h context, void *data)
224 {
225   Internal::Adaptor::Widget* widget = static_cast< Internal::Adaptor::Widget* >( data );
226   bundle* bundleData;
227   bundle* contentData = NULL;
228   char* operation = NULL;
229   char* content = NULL;
230   char* widthStr = NULL;
231   char* heightStr = NULL;
232   char* remain = NULL;
233   uint32_t width = 0;
234   uint32_t height = 0;
235
236   // currently, there is no implementaion in appcore;
237   appcore_multiwindow_base_class_on_create(context);
238
239   const char* id = appcore_multiwindow_base_instance_get_id(context);
240   bundle* createBundle = static_cast<bundle*>(appcore_multiwindow_base_instance_get_extra(context));
241
242   Dali::WidgetData widgetData = Dali::WidgetData::New( id, createBundle, NULL );
243
244   char* createContent = NULL;
245   bundle_get_str(createBundle, "__WIDGET_CONTENT_INFO__", &createContent);
246   if(createContent)
247   {
248     widgetData.SetContent( const_cast<char *>(std::string(createContent).c_str()) );
249   }
250   widget->InsertWidgetData( id, widgetData );
251
252   bundleData = widgetData.GetArgs();
253   bundle_get_str(bundleData, "__WIDGET_OP__", &operation);
254
255   if(!operation)
256   {
257     DALI_LOG_ERROR("no operation provided");
258     return;
259   }
260
261   bundle_get_str(bundleData, "__WIDGET_CONTENT_INFO__", &content);
262   bundle_get_str(bundleData, "__WIDGET_WIDTH__", &widthStr);
263   bundle_get_str(bundleData, "__WIDGET_HEIGHT__", &heightStr);
264
265   if(widthStr)
266     width = static_cast<uint32_t>(g_ascii_strtoll(widthStr, &remain, 10));
267
268   if(heightStr)
269     height = static_cast<uint32_t>(g_ascii_strtoll(heightStr, &remain, 10));
270
271   if(content)
272 #pragma GCC diagnostic push
273 #pragma GCC diagnostic ignored "-Wold-style-cast"
274     contentData = bundle_decode((const bundle_raw*)content, strlen(content));
275 #pragma GCC diagnostic pop
276
277   Any nativeHandle = Dali::Adaptor::Get().GetNativeWindowHandle();
278   Ecore_Wl_Window * wlWindow = AnyCast<Ecore_Wl_Window*>( nativeHandle );
279
280   struct wl_surface* surface = ecore_wl_window_surface_get(wlWindow);
281
282   screen_connector_provider_remote_enable(id, surface);
283   ecore_wl_window_class_name_set(wlWindow, id);
284   appcore_multiwindow_base_window_bind( context, wlWindow );
285
286   if(!widget->mCreateSignal.Empty())
287   {
288     widget->mCreateSignal.Emit(widgetData, contentData, Dali::Widget::WindowSize(width, height));
289   }
290
291   SendUpdateStatus(widget->mClassId.c_str(), const_cast<char*>(id), AUL_WIDGET_INSTANCE_EVENT_CREATE, NULL);
292
293   aul_widget_instance_add(widget->mClassId.c_str(), const_cast<char*>(id));
294
295   if(contentData)
296     bundle_free(contentData);
297 }
298
299 static void OnTerminate(appcore_multiwindow_base_instance_h context, void *data)
300 {
301   bundle* bundleData;
302   char* operation = NULL;
303   bundle* contentData;
304
305   Dali::Widget::WidgetTerminateType reason = Dali::Widget::WidgetTerminateType::TEMPORARY;
306   int event = AUL_WIDGET_INSTANCE_EVENT_TERMINATE;
307   const char* id;
308
309   id = appcore_multiwindow_base_instance_get_id(context);
310
311   Internal::Adaptor::Widget* widget = static_cast< Internal::Adaptor::Widget* >( data );
312
313   Dali::WidgetData* widgetData = widget->FindWidgetData(id);
314
315   bundleData = widgetData->GetArgs();
316
317   if(bundleData)
318   {
319     bundle_get_str(bundleData, "__WIDGET_OP__", &operation);
320     if (operation && strcmp(operation, "destroy") == 0)
321     {
322       reason = Dali::Widget::WidgetTerminateType::PERMANENT;
323     }
324   }
325
326   char* content = widgetData->GetContent();
327   if( content )
328   {
329 #pragma GCC diagnostic push
330 #pragma GCC diagnostic ignored "-Wold-style-cast"
331     contentData = bundle_decode((const bundle_raw *)content, strlen(content));
332 #pragma GCC diagnostic pop
333   }
334   else
335   {
336     contentData = bundle_create();
337   }
338
339   if(!widget->mTerminateSignal.Empty())
340   {
341     widget->mTerminateSignal.Emit(*widgetData, contentData, reason );
342   }
343
344   if(reason == Dali::Widget::WidgetTerminateType::PERMANENT)
345   {
346     event = AUL_WIDGET_INSTANCE_EVENT_DESTROY;
347     aul_widget_instance_del(widget->mClassId.c_str(), id);
348   }
349   else
350   {
351     SendUpdateStatus(widget->mClassId.c_str(), id, AUL_WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, contentData);
352   }
353
354   if(contentData)
355   {
356     bundle_free(contentData);
357   }
358
359   SendUpdateStatus(widget->mClassId.c_str(), id, event, NULL);
360
361   // currently, there is no implementaion in appcore;
362   appcore_multiwindow_base_class_on_terminate(context);
363   widget->DeleteWidgetData(id);
364 }
365
366 static void OnPause(appcore_multiwindow_base_instance_h context, void *data)
367 {
368   // currently, there is no implementaion in appcore;
369   appcore_multiwindow_base_class_on_pause(context);
370
371   const char *id = appcore_multiwindow_base_instance_get_id(context);
372   Internal::Adaptor::Widget* widget = static_cast< Internal::Adaptor::Widget* >( data );
373
374   Dali::WidgetData* widgetData = widget->FindWidgetData(id);
375
376   if(!widget->mPauseSignal.Empty())
377   {
378     widget->mPauseSignal.Emit(*widgetData);
379   }
380
381   SendUpdateStatus(widget->mClassId.c_str(), id, AUL_WIDGET_INSTANCE_EVENT_PAUSE, NULL);
382 }
383
384 static void OnResume(appcore_multiwindow_base_instance_h context, void *data)
385 {
386   // currently, there is no implementaion in appcore;
387   appcore_multiwindow_base_class_on_resume(context);
388
389   const char *id = appcore_multiwindow_base_instance_get_id(context);
390   Internal::Adaptor::Widget* widget = static_cast< Internal::Adaptor::Widget* >( data );
391
392   Dali::WidgetData* widgetData = widget->FindWidgetData(id);
393
394   if(!widget->mResumeSignal.Empty())
395   {
396     widget->mResumeSignal.Emit(*widgetData);
397   }
398
399   SendUpdateStatus(widget->mClassId.c_str(), id, AUL_WIDGET_INSTANCE_EVENT_RESUME, NULL);
400 }
401
402 void Widget::OnResize(appcore_multiwindow_base_instance_h context, Dali::Widget::WindowSize windowSize)
403 {
404   const char *id = appcore_multiwindow_base_instance_get_id(context);
405   Dali::WidgetData *widgetData = FindWidgetData(id);
406
407   if(!mResizeSignal.Empty())
408   {
409     mResizeSignal.Emit(*widgetData, windowSize);
410   }
411
412   SendUpdateStatus(mClassId.c_str(), id, AUL_WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL);
413 }
414
415 void Widget::OnUpdate(appcore_multiwindow_base_instance_h context, bundle* content, int force)
416 {
417   const char *id = appcore_multiwindow_base_instance_get_id(context);
418   Dali::WidgetData *widgetData = static_cast<Dali::WidgetData*>(appcore_multiwindow_base_instance_get_extra(context));
419
420   if(!mUpdateSignal.Empty())
421   {
422     mUpdateSignal.Emit(*widgetData, content, force);
423   }
424
425   SendUpdateStatus(mClassId.c_str(), id, AUL_WIDGET_INSTANCE_EVENT_UPDATE, NULL);
426 }
427
428 Widget::Widget( const std::string& id )
429 : mCreateSignal(),
430   mTerminateSignal(),
431   mPauseSignal(),
432   mResumeSignal(),
433   mResizeSignal(),
434   mUpdateSignal(),
435   mClassId(id),
436   mSlotDelegate(this)
437 {
438   appcore_multiwindow_base_class cls;
439
440   cls.id = const_cast<char*>(mClassId.c_str());
441   cls.data = this;
442   cls.create = OnInit;
443   cls.terminate = OnTerminate;
444   cls.pause = OnPause;
445   cls.resume = OnResume;
446
447   appcore_multiwindow_base_class_add(cls);
448 }
449
450 Widget::~Widget()
451 {
452 }
453
454 } // Adaptor
455
456 } // Internal
457
458 } // Dali