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