2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "wrt-client.h"
17 #include <appcore-efl.h>
21 #include <dpl/log/log.h>
22 #include <dpl/optional_typedefs.h>
23 #include <dpl/exception.h>
24 #include <common/application_data.h>
25 #include <core_module.h>
26 #include <localization_setting.h>
27 #include <widget_deserialize_model.h>
29 #include <dpl/localization/w3c_file_localization.h>
30 #include <dpl/localization/LanguageTagsProvider.h>
32 //W3C PACKAGING enviroment variable name
33 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
35 // window signal callback
36 const char *EDJE_SHOW_BACKWARD_SIGNAL = "show,backward,signal";
37 const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
38 const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized";
39 char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content";
40 const char* const BUNDLE_PATH = "/usr/lib/wrt-wk2-bundles/libwrt-wk2-bundle.so";
42 static Ewk_Context* s_ewk_context = NULL;
44 WrtClient::WrtClient(int argc, char **argv) :
45 Application(argc, argv, "wrt-client", false),
46 DPL::TaskDecl<WrtClient>(this),
48 m_initializing(false),
53 m_returnStatus(ReturnStatus::Succeeded),
54 m_widgetState(WidgetState::WidgetState_Stopped)
57 LogDebug("App Created");
60 WrtClient::~WrtClient()
62 LogDebug("App Finished");
65 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
67 return m_returnStatus;
70 void WrtClient::OnStop()
72 LogInfo("Stopping Dummy Client");
75 void WrtClient::OnCreate()
78 ADD_PROFILING_POINT("OnCreate callback", "point");
82 void WrtClient::OnResume()
84 if (m_widgetState != WidgetState_Suspended) {
85 LogWarning("Widget is not suspended, resuming was skipped");
89 m_widgetState = WidgetState_Running;
92 void WrtClient::OnPause()
96 if (m_widgetState != WidgetState_Running) {
97 LogWarning("Widget is not running to be suspended");
101 m_widgetState = WidgetState_Suspended;
104 void WrtClient::OnReset(bundle *b)
107 // bundle argument is freed after OnReset() is returned
108 // So bundle duplication is needed
109 ApplicationDataSingleton::Instance().setBundle(bundle_dup(b));
111 if (true == m_initializing) {
112 LogDebug("can not handle reset event");
115 if (true == m_launched) {
116 if (m_widgetState == WidgetState_Stopped) {
117 LogError("Widget is not running to be reset");
121 m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
122 m_widgetState = WidgetState_Running;
124 if (true == checkArgument()) {
132 void WrtClient::OnTerminate()
134 LogDebug("Wrt Shutdown now");
138 void WrtClient::showHelpAndQuit()
140 printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
142 "Mandatory arguments to long options are mandatory for short "
144 " -h, --help show this help\n"
146 "launch widget with given tizen ID\n"
148 "launch widget with given tizen ID\n"
154 bool WrtClient::checkArgument()
156 std::string tizenId = getTizenIdFromArgument(m_argc, m_argv);
158 if (tizenId.empty()) {
163 LogDebug("Tizen id: " << m_tizenId);
168 std::string WrtClient::getTizenIdFromArgument(int argc, char **argv)
170 LogInfo("checkArgument");
171 std::string arg = argv[0];
177 if (arg.find("wrt-client") != std::string::npos) {
184 if (arg == "-h" || arg == "--help") {
186 } else if (arg == "-l" || arg == "--launch" ||
187 arg == "-t" || arg == "--tizen")
197 // Launch widget based on application basename
198 size_t pos = arg.find_last_of('/');
200 if (pos != std::string::npos) {
201 arg = arg.erase(0, pos + 1);
208 void WrtClient::setStep()
212 AddStep(&WrtClient::initStep);
214 setSdkLauncherDebugData();
216 AddStep(&WrtClient::launchStep);
217 AddStep(&WrtClient::shutdownStep);
219 m_initializing = true;
221 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
224 void WrtClient::setSdkLauncherDebugData()
226 LogDebug("setSdkLauncherDebugData");
228 /* check bundle from sdk launcher */
229 bundle *bundleFromSdkLauncher;
230 bundleFromSdkLauncher = bundle_import_from_argv(m_argc, m_argv);
231 const char *bundle_debug = bundle_get_val(bundleFromSdkLauncher, "debug");
232 const char *bundle_pid = bundle_get_val(bundleFromSdkLauncher, "pid");
233 if (bundle_debug != NULL && bundle_pid != NULL) {
234 if (strcmp(bundle_debug, "true") == 0) {
236 m_sdkLauncherPid = atoi(bundle_pid);
241 bundle_free(bundleFromSdkLauncher);
244 bool WrtClient::checkDebugMode(SDKDebugData* debugData)
246 LogError("Checking for debug mode");
249 bool debugMode = debugData->debugMode;
251 LogInfo("[DEBUG_MODE] Widget is launched in " <<
252 (debugMode ? "DEBUG" : "RETAIL") <<
255 if (debugMode == true) {
256 // In WAC widget, only test widgets can use web inspector.
258 // every launched widgets as debug mode can use it.
259 if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_WAC20) {
261 WRT::CoreModuleSingleton::Instance().developerMode();
262 //This code will be activated
263 //after WAC test certificate is used by SDK
264 //bool isTestWidget = view->m_widgetModel->IsTestWidget.Get();
267 // LogInfo("This is not WAC Test Widget");
270 if (!developerMode) {
271 LogInfo("This is not WAC Developer Mode");
279 void WrtClient::OnEventReceived(const NextStepEvent& /*event*/)
281 LogDebug("Executing next step");
285 void WrtClient::initStep()
288 if (WRT::CoreModuleSingleton::Instance().Init(s_ewk_context)) {
289 m_initialized = true;
291 m_returnStatus = ReturnStatus::Failed;
292 SwitchToStep(&WrtClient::shutdownStep);
295 // ecore_event_jobs are processed sequentially without concession to
296 // other type events. To give a chance of execute to other events,
297 // ecore_timer_add was used.
298 DPL::Event::ControllerEventHandler<NextStepEvent>::PostTimedEvent(
299 NextStepEvent(), 0.001);
302 bool WrtClient::checkWACTestCertififedWidget()
304 // WAC Waikiki Beta Release Core Specification: Widget Runtime
307 // WR-4710 The WRT MUST enable debug functions only for WAC test widgets
308 // i.e. the functions must not be usable for normal WAC widgets, even when
309 // a WAC test widget is executing.
310 ADD_PROFILING_POINT("DeveloperModeCheck", "start");
313 // A widget signed with a WAC-issued test certificate as described in
316 bool developerWidget = m_dao->isTestWidget();
317 bool developerMode = WRT::CoreModuleSingleton::Instance().developerMode();
319 LogDebug("Is WAC test widget: " << developerWidget);
320 LogDebug("Is developer Mode: " << developerMode);
322 if (developerWidget) {
323 if (!developerMode) {
324 LogError("WAC test certified developer widget is needed for " <<
328 //TODO: WR-4660 (show popup about developer widget
330 LogInfo("POPUP: THIS IS TEST WIDGET!");
333 ADD_PROFILING_POINT("DeveloperModeCheck", "stop");
337 void WrtClient::loadFinishCallback(Evas_Object* webview)
339 ADD_PROFILING_POINT("loadFinishCallback", "start");
340 SDKDebugData* debug = new SDKDebugData;
341 debug->debugMode = m_debugMode;
342 debug->pid = new unsigned long(getpid());
344 LogInfo("Post result of launch");
346 // Start inspector server, if current mode is debugger mode.
347 // In the WK2 case, ewk_view_inspector_server_start should
348 // be called after WebProcess is created.
349 if (checkDebugMode(debug)) {
351 ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0);
352 if (debug->portnum == 0) {
353 LogWarning("Failed to get portnum");
355 LogInfo("Assigned port number for inspector : "
359 LogDebug("Debug mode is disabled");
362 //w3c packaging test debug (message on 4>)
363 const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE);
364 if (makeScreen != NULL && strcmp(makeScreen, "1") == 0) {
365 FILE* doutput = fdopen(4, "w");
366 fprintf(doutput, "didFinishLoadForFrameCallback: ready\n");
371 LogDebug("Launch succesfull");
374 m_initializing = false;
376 ADD_PROFILING_POINT("loadFinishCallback", "stop");
377 printf("launched\n");
382 m_returnStatus = ReturnStatus::Failed;
384 DPL::Event::ControllerEventHandler<NextStepEvent>::
385 PostEvent(NextStepEvent());
388 if (debug->debugMode) {
389 LogDebug("Send RT signal to wrt-launcher(pid: " << m_sdkLauncherPid);
391 /* send real time signal with result to wrt-launcher */
393 LogDebug("userData->portnum : " << debug->portnum);
394 sv.sival_int = debug->portnum;
398 sigqueue(m_sdkLauncherPid, SIGRTMIN, sv);
401 ApplicationDataSingleton::Instance().freeBundle();
403 LogDebug("Cleaning wrtClient launch resources...");
408 void WrtClient::progressFinishCallback()
410 m_splashScreen->stopSplashScreen();
413 void WrtClient::webkitExitCallback()
415 LogDebug("window close called, terminating app");
416 SwitchToStep(&WrtClient::shutdownStep);
417 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
421 void WrtClient::webCrashCallback()
423 LogError("webProcess crashed");
424 SwitchToStep(&WrtClient::shutdownStep);
425 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
429 void WrtClient::launchStep()
431 ADD_PROFILING_POINT("launchStep", "start");
432 LogDebug("Launching widget ...");
434 ADD_PROFILING_POINT("getRunnableWidgetObject", "start");
435 m_widget = WRT::CoreModuleSingleton::Instance()
436 .getRunnableWidgetObject(m_tizenId);
437 ADD_PROFILING_POINT("getRunnableWidgetObject", "stop");
440 LogError("RunnableWidgetObject is NULL, stop launchStep");
441 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
446 if (m_widgetState == WidgetState_Running) {
447 LogWarning("Widget already running, stop launchStep");
448 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
453 if (m_widgetState == WidgetState_Authorizing) {
454 LogWarning("Widget already authorizing, stop launchStep");
455 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
460 m_dao.reset(new WrtDB::WidgetDAOReadOnly(DPL::FromASCIIString(m_tizenId)));
461 DPL::Optional<DPL::String> defloc = m_dao->getDefaultlocale();
462 if (!defloc.IsNull()) {
463 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
467 // For localizationsetting not changed on widget running
468 //LocalizationSetting::SetLanguageChangedCallback(
469 // languageChangedCallback, this);
471 ADD_PROFILING_POINT("CreateWindow", "start");
472 m_windowData.reset(new WindowData(static_cast<unsigned long>(getpid()),
474 ADD_PROFILING_POINT("CreateWindow", "stop");
476 WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
477 ADD_PROFILING_POINT("Create splash screen", "start");
478 m_splashScreen.reset(
479 new SplashScreenSupport(m_windowData->m_win));
480 if (m_splashScreen->createSplashScreen(m_dao->getSplashImgSrc())) {
481 m_splashScreen->startSplashScreen();
482 cbs->progressFinish = DPL::MakeDelegate(
485 progressFinishCallback);
487 ADD_PROFILING_POINT("Create splash screen", "stop");
488 DPL::OptionalString startUrl = W3CFileLocalization::getStartFile(m_dao);
489 if (!m_widget->PrepareView(DPL::ToUTF8String(*startUrl),
490 m_windowData->m_win))
492 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
496 //you can't show window with splash screen before PrepareView
497 //ewk_view_add_with_context() in viewLogic breaks window
499 m_windowData->init();
501 WrtDB::WidgetLocalizedInfo localizedInfo =
502 W3CFileLocalization::getLocalizedInfo(m_dao);
503 std::string name = "";
504 if (!(localizedInfo.name.IsNull())) {
505 name = DPL::ToUTF8String(*(localizedInfo.name));
507 elm_win_title_set(m_windowData->m_win, name.c_str());
508 evas_object_show(m_windowData->m_win);
509 initializeWindowModes();
510 connectElmCallback();
512 if (!checkWACTestCertififedWidget()) {
513 LogWarning("WAC Certificate failed, stop launchStep");
517 m_widgetState = WidgetState_Authorizing;
518 if (!m_widget->CheckBeforeLaunch()) {
519 LogError("CheckBeforeLaunch failed, stop launchStep");
520 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
524 LogInfo("Widget launch accepted. Entering running state");
525 m_widgetState = WidgetState_Running;
527 cbs->loadFinish = DPL::MakeDelegate(this, &WrtClient::loadFinishCallback);
528 cbs->bufferSet = DPL::MakeDelegate(this, &WrtClient::setLayout);
529 cbs->bufferUnset = DPL::MakeDelegate(this, &WrtClient::unsetLayout);
530 cbs->webkitExit = DPL::MakeDelegate(this, &WrtClient::webkitExitCallback);
531 cbs->webCrash = DPL::MakeDelegate(this, &WrtClient::webCrashCallback);
532 cbs->toggleFullscreen = DPL::MakeDelegate(
533 m_windowData.get(), &WindowData::toggleFullscreen);
535 m_widget->SetUserDelegates(cbs);
537 m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
538 ADD_PROFILING_POINT("launchStep", "stop");
541 void WrtClient::initializeWindowModes()
543 Assert(m_windowData);
545 auto windowModes = m_dao->getWindowModes();
546 bool fullscreen = false;
547 bool backbutton = false;
548 if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
549 WidgetSettings widgetSettings;
550 m_dao->getWidgetSettings(widgetSettings);
551 WidgetSettingList settings(widgetSettings);
553 (settings.getBackButtonPresence() == BackButton_Enable);
556 FOREACH(it, windowModes)
558 std::string viewMode = DPL::ToUTF8String(*it);
559 if (viewMode == VIEWMODE_TYPE_FULLSCREEN) {
562 } else if (viewMode == VIEWMODE_TYPE_MAXIMIZED) {
567 m_windowData->setViewMode(fullscreen,
571 void WrtClient::backButtonCallback(void* data,
572 Evas_Object * /*obj*/,
573 void * /*event_info*/)
575 LogInfo("BackButtonCallback");
578 WrtClient* This = static_cast<WrtClient*>(data);
580 This->m_widget->Backward();
583 void WrtClient::connectElmCallback()
585 Assert(m_windowData);
587 if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
588 WidgetSettings widgetSettings;
589 m_dao->getWidgetSettings(widgetSettings);
590 WidgetSettingList settings(widgetSettings);
591 if (settings.getBackButtonPresence() == BackButton_Enable) {
592 m_windowData->addFloatBackButtonCallback(
594 &WrtClient::backButtonCallback,
598 WidgetSettingScreenLock rotationValue = settings.getRotationValue();
599 if (rotationValue == Screen_Portrait) {
600 elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
601 } else if (rotationValue == Screen_Landscape) {
602 elm_win_rotation_with_resize_set(m_windowData->m_win, 270);
604 elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
609 void WrtClient::setLayout(Evas_Object* newBuffer)
611 LogDebug("add new webkit buffer to window");
614 elm_object_part_content_set(m_windowData->m_user_layout,
618 evas_object_show(newBuffer);
621 void WrtClient::unsetLayout(Evas_Object* currentBuffer)
623 LogDebug("remove current webkit buffer from window");
624 Assert(currentBuffer);
625 evas_object_hide(currentBuffer);
627 elm_object_part_content_unset(m_windowData->m_user_layout,
628 ELM_SWALLOW_CONTENT);
631 void WrtClient::shutdownStep()
633 LogDebug("Closing Wrt connection ...");
635 if (m_widget && m_widgetState) {
636 m_widgetState = WidgetState_Stopped;
639 WRT::CoreModuleSingleton::Instance().Terminate();
642 m_initialized = false;
644 m_windowData.reset();
648 int WrtClient::languageChangedCallback(void *data)
650 LogDebug("Language Changed");
654 WrtClient* wrtClient = static_cast<WrtClient*>(data);
655 if (!(wrtClient->m_dao)) {
659 // reset function fetches system locales and recreates language tags
660 LanguageTagsProviderSingleton::Instance().resetLanguageTags();
661 // widget default locales are added to language tags below
662 DPL::OptionalString defloc = wrtClient->m_dao->getDefaultlocale();
663 if (!defloc.IsNull()) {
664 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
668 if (wrtClient->m_launched &&
669 wrtClient->m_widgetState != WidgetState_Stopped)
671 wrtClient->m_widget->ReloadStartPage();
676 void WrtClient::Quit()
679 DPL::Application::Quit();
685 UNHANDLED_EXCEPTION_HANDLER_BEGIN
687 ADD_PROFILING_POINT("main-entered", "point");
690 DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
692 // set evas backend type
693 if (!getenv("ELM_ENGINE")) {
694 if (!setenv("ELM_ENGINE", "gl", 1)) {
695 LogDebug("Enable backend");
698 LogDebug("ELM_ENGINE : " << getenv("ELM_ENGINE"));
702 setenv("COREGL_FASTPATH", "1", 1);
704 setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
705 setenv("CAIRO_GL_LAZY_FLUSHING", "yes", 1);
706 setenv("ELM_IMAGE_CACHE", "0", 1);
708 // This code is to fork a web process without exec.
709 std::string tizenId = WrtClient::getTizenIdFromArgument(argc, argv);
711 if (!tizenId.empty()) {
712 LogDebug("Launching by fork mode");
713 // Language env setup
714 appcore_set_i18n("wrt-client", NULL);
716 ewk_set_arguments(argc, argv);
717 setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
718 s_ewk_context = ewk_context_new_with_injected_bundle_path(
722 // Output on stdout will be flushed after every newline character,
723 // even if it is redirected to a pipe. This is useful for running
724 // from a script and parsing output.
725 // (Standard behavior of stdlib is to use full buffering when
726 // redirected to a pipe, which means even after an end of line
727 // the output may not be flushed).
730 WrtClient app(argc, argv);
732 ADD_PROFILING_POINT("Before appExec", "point");
733 int ret = app.Exec();
734 LogDebug("App returned: " << ret);
735 ret = app.getReturnStatus();
736 LogDebug("WrtClient returned: " << ret);
739 UNHANDLED_EXCEPTION_HANDLER_END