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>
18 #include <appcore-common.h>
22 #include <dpl/log/log.h>
23 #include <dpl/optional_typedefs.h>
24 #include <dpl/exception.h>
25 #include <common/application_data.h>
26 #include <core_module.h>
27 #include <localization_setting.h>
28 #include <widget_deserialize_model.h>
30 #include <dpl/localization/w3c_file_localization.h>
31 #include <dpl/localization/LanguageTagsProvider.h>
32 #include "webkit/bundles/plugin_module_support.h"
34 //W3C PACKAGING enviroment variable name
35 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
37 // window signal callback
38 const char *EDJE_SHOW_BACKWARD_SIGNAL = "show,backward,signal";
39 const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
40 const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized";
41 char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content";
42 const char* const BUNDLE_PATH = "/usr/lib/wrt-wk2-bundles/libwrt-wk2-bundle.so";
44 static Ewk_Context* s_ewk_context = NULL;
46 WrtClient::WrtClient(int argc, char **argv) :
47 Application(argc, argv, "wrt-client", false),
48 DPL::TaskDecl<WrtClient>(this),
50 m_initializing(false),
55 m_returnStatus(ReturnStatus::Succeeded),
56 m_widgetState(WidgetState::WidgetState_Stopped)
59 LogDebug("App Created");
62 WrtClient::~WrtClient()
64 LogDebug("App Finished");
67 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
69 return m_returnStatus;
72 void WrtClient::OnStop()
74 LogInfo("Stopping Dummy Client");
77 void WrtClient::OnCreate()
80 ADD_PROFILING_POINT("OnCreate callback", "point");
84 void WrtClient::OnResume()
86 if (m_widgetState != WidgetState_Suspended) {
87 LogWarning("Widget is not suspended, resuming was skipped");
91 m_widgetState = WidgetState_Running;
94 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()) {
131 // low memory callback set
132 appcore_set_event_callback(
133 APPCORE_EVENT_LOW_MEMORY,
134 WrtClient::appcoreLowMemoryCallback,
138 void WrtClient::OnTerminate()
140 LogDebug("Wrt Shutdown now");
144 void WrtClient::showHelpAndQuit()
146 printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
148 "Mandatory arguments to long options are mandatory for short "
150 " -h, --help show this help\n"
152 "launch widget with given tizen ID\n"
154 "launch widget with given tizen ID\n"
160 bool WrtClient::checkArgument()
162 std::string tizenId = getTizenIdFromArgument(m_argc, m_argv);
164 if (tizenId.empty()) {
169 LogDebug("Tizen id: " << m_tizenId);
174 std::string WrtClient::getTizenIdFromArgument(int argc, char **argv)
176 LogInfo("checkArgument");
177 std::string arg = argv[0];
183 if (arg.find("wrt-client") != std::string::npos) {
190 if (arg == "-h" || arg == "--help") {
192 } else if (arg == "-l" || arg == "--launch" ||
193 arg == "-t" || arg == "--tizen")
203 // Launch widget based on application basename
204 size_t pos = arg.find_last_of('/');
206 if (pos != std::string::npos) {
207 arg = arg.erase(0, pos + 1);
214 void WrtClient::setStep()
218 AddStep(&WrtClient::initStep);
220 setSdkLauncherDebugData();
222 AddStep(&WrtClient::launchStep);
223 AddStep(&WrtClient::shutdownStep);
225 m_initializing = true;
227 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
230 void WrtClient::setSdkLauncherDebugData()
232 LogDebug("setSdkLauncherDebugData");
234 /* check bundle from sdk launcher */
235 bundle *bundleFromSdkLauncher;
236 bundleFromSdkLauncher = bundle_import_from_argv(m_argc, m_argv);
237 const char *bundle_debug = bundle_get_val(bundleFromSdkLauncher, "debug");
238 const char *bundle_pid = bundle_get_val(bundleFromSdkLauncher, "pid");
239 if (bundle_debug != NULL && bundle_pid != NULL) {
240 if (strcmp(bundle_debug, "true") == 0) {
242 m_sdkLauncherPid = atoi(bundle_pid);
247 bundle_free(bundleFromSdkLauncher);
250 bool WrtClient::checkDebugMode(SDKDebugData* debugData)
252 LogError("Checking for debug mode");
255 bool debugMode = debugData->debugMode;
257 LogInfo("[DEBUG_MODE] Widget is launched in " <<
258 (debugMode ? "DEBUG" : "RETAIL") <<
261 if (debugMode == true) {
262 // In WAC widget, only test widgets can use web inspector.
264 // every launched widgets as debug mode can use it.
265 if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_WAC20) {
267 WRT::CoreModuleSingleton::Instance().developerMode();
268 //This code will be activated
269 //after WAC test certificate is used by SDK
270 //bool isTestWidget = view->m_widgetModel->IsTestWidget.Get();
273 // LogInfo("This is not WAC Test Widget");
276 if (!developerMode) {
277 LogInfo("This is not WAC Developer Mode");
285 void WrtClient::OnEventReceived(const NextStepEvent& /*event*/)
287 LogDebug("Executing next step");
291 void WrtClient::initStep()
294 if (WRT::CoreModuleSingleton::Instance().Init()) {
295 m_initialized = true;
297 m_returnStatus = ReturnStatus::Failed;
298 SwitchToStep(&WrtClient::shutdownStep);
301 // ecore_event_jobs are processed sequentially without concession to
302 // other type events. To give a chance of execute to other events,
303 // ecore_timer_add was used.
304 DPL::Event::ControllerEventHandler<NextStepEvent>::PostTimedEvent(
305 NextStepEvent(), 0.001);
308 bool WrtClient::checkWACTestCertififedWidget()
310 // WAC Waikiki Beta Release Core Specification: Widget Runtime
313 // WR-4710 The WRT MUST enable debug functions only for WAC test widgets
314 // i.e. the functions must not be usable for normal WAC widgets, even when
315 // a WAC test widget is executing.
316 ADD_PROFILING_POINT("DeveloperModeCheck", "start");
319 // A widget signed with a WAC-issued test certificate as described in
322 bool developerWidget = m_dao->isTestWidget();
323 bool developerMode = WRT::CoreModuleSingleton::Instance().developerMode();
325 LogDebug("Is WAC test widget: " << developerWidget);
326 LogDebug("Is developer Mode: " << developerMode);
328 if (developerWidget) {
329 if (!developerMode) {
330 LogError("WAC test certified developer widget is needed for " <<
334 //TODO: WR-4660 (show popup about developer widget
336 LogInfo("POPUP: THIS IS TEST WIDGET!");
339 ADD_PROFILING_POINT("DeveloperModeCheck", "stop");
343 void WrtClient::loadFinishCallback(Evas_Object* webview)
345 ADD_PROFILING_POINT("loadFinishCallback", "start");
346 SDKDebugData* debug = new SDKDebugData;
347 debug->debugMode = m_debugMode;
348 debug->pid = new unsigned long(getpid());
350 LogInfo("Post result of launch");
352 // Start inspector server, if current mode is debugger mode.
353 // In the WK2 case, ewk_view_inspector_server_start should
354 // be called after WebProcess is created.
355 if (checkDebugMode(debug)) {
357 ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0);
358 if (debug->portnum == 0) {
359 LogWarning("Failed to get portnum");
361 LogInfo("Assigned port number for inspector : "
365 LogDebug("Debug mode is disabled");
368 //w3c packaging test debug (message on 4>)
369 const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE);
370 if (makeScreen != NULL && strcmp(makeScreen, "1") == 0) {
371 FILE* doutput = fdopen(4, "w");
372 fprintf(doutput, "didFinishLoadForFrameCallback: ready\n");
377 LogDebug("Launch succesfull");
380 m_initializing = false;
382 ADD_PROFILING_POINT("loadFinishCallback", "stop");
383 printf("launched\n");
388 m_returnStatus = ReturnStatus::Failed;
390 DPL::Event::ControllerEventHandler<NextStepEvent>::
391 PostEvent(NextStepEvent());
394 if (debug->debugMode) {
395 LogDebug("Send RT signal to wrt-launcher(pid: " << m_sdkLauncherPid);
397 /* send real time signal with result to wrt-launcher */
399 LogDebug("userData->portnum : " << debug->portnum);
400 sv.sival_int = debug->portnum;
404 sigqueue(m_sdkLauncherPid, SIGRTMIN, sv);
407 ApplicationDataSingleton::Instance().freeBundle();
409 LogDebug("Cleaning wrtClient launch resources...");
414 void WrtClient::progressFinishCallback()
416 m_splashScreen->stopSplashScreen();
419 void WrtClient::webkitExitCallback()
421 LogDebug("window close called, terminating app");
422 SwitchToStep(&WrtClient::shutdownStep);
423 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
427 void WrtClient::webCrashCallback()
429 LogError("webProcess crashed");
430 SwitchToStep(&WrtClient::shutdownStep);
431 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
435 void WrtClient::launchStep()
437 ADD_PROFILING_POINT("launchStep", "start");
438 LogDebug("Launching widget ...");
440 ADD_PROFILING_POINT("getRunnableWidgetObject", "start");
441 m_widget = WRT::CoreModuleSingleton::Instance()
442 .getRunnableWidgetObject(m_tizenId);
443 ADD_PROFILING_POINT("getRunnableWidgetObject", "stop");
446 LogError("RunnableWidgetObject is NULL, stop launchStep");
447 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
452 if (m_widgetState == WidgetState_Running) {
453 LogWarning("Widget already running, stop launchStep");
454 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
459 if (m_widgetState == WidgetState_Authorizing) {
460 LogWarning("Widget already authorizing, stop launchStep");
461 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
466 m_dao.reset(new WrtDB::WidgetDAOReadOnly(DPL::FromASCIIString(m_tizenId)));
467 DPL::Optional<DPL::String> defloc = m_dao->getDefaultlocale();
468 if (!defloc.IsNull()) {
469 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
473 // For localizationsetting not changed on widget running
474 //LocalizationSetting::SetLanguageChangedCallback(
475 // languageChangedCallback, this);
477 ADD_PROFILING_POINT("CreateWindow", "start");
478 m_windowData.reset(new WindowData(static_cast<unsigned long>(getpid()),
480 ADD_PROFILING_POINT("CreateWindow", "stop");
482 WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
483 ADD_PROFILING_POINT("Create splash screen", "start");
484 m_splashScreen.reset(
485 new SplashScreenSupport(m_windowData->m_win));
486 if (m_splashScreen->createSplashScreen(m_dao->getSplashImgSrc())) {
487 m_splashScreen->startSplashScreen();
488 cbs->progressFinish = DPL::MakeDelegate(
491 progressFinishCallback);
493 ADD_PROFILING_POINT("Create splash screen", "stop");
494 DPL::OptionalString startUrl = W3CFileLocalization::getStartFile(m_dao);
495 if (!m_widget->PrepareView(DPL::ToUTF8String(*startUrl),
496 m_windowData->m_win, s_ewk_context))
498 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
502 //you can't show window with splash screen before PrepareView
503 //ewk_view_add_with_context() in viewLogic breaks window
505 m_windowData->init();
507 WrtDB::WidgetLocalizedInfo localizedInfo =
508 W3CFileLocalization::getLocalizedInfo(m_dao);
509 std::string name = "";
510 if (!(localizedInfo.name.IsNull())) {
511 name = DPL::ToUTF8String(*(localizedInfo.name));
513 elm_win_title_set(m_windowData->m_win, name.c_str());
514 evas_object_show(m_windowData->m_win);
515 initializeWindowModes();
516 connectElmCallback();
518 if (!checkWACTestCertififedWidget()) {
519 LogWarning("WAC Certificate failed, stop launchStep");
523 m_widgetState = WidgetState_Authorizing;
524 if (!m_widget->CheckBeforeLaunch()) {
525 LogError("CheckBeforeLaunch failed, stop launchStep");
526 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
530 LogInfo("Widget launch accepted. Entering running state");
531 m_widgetState = WidgetState_Running;
533 cbs->loadFinish = DPL::MakeDelegate(this, &WrtClient::loadFinishCallback);
534 cbs->bufferSet = DPL::MakeDelegate(this, &WrtClient::setLayout);
535 cbs->bufferUnset = DPL::MakeDelegate(this, &WrtClient::unsetLayout);
536 cbs->webkitExit = DPL::MakeDelegate(this, &WrtClient::webkitExitCallback);
537 cbs->webCrash = DPL::MakeDelegate(this, &WrtClient::webCrashCallback);
538 cbs->toggleFullscreen = DPL::MakeDelegate(
539 m_windowData.get(), &WindowData::toggleFullscreen);
541 m_widget->SetUserDelegates(cbs);
543 m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
544 ADD_PROFILING_POINT("launchStep", "stop");
547 void WrtClient::initializeWindowModes()
549 Assert(m_windowData);
551 auto windowModes = m_dao->getWindowModes();
552 bool fullscreen = false;
553 bool backbutton = false;
554 if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
555 WidgetSettings widgetSettings;
556 m_dao->getWidgetSettings(widgetSettings);
557 WidgetSettingList settings(widgetSettings);
559 (settings.getBackButtonPresence() == BackButton_Enable);
562 FOREACH(it, windowModes)
564 std::string viewMode = DPL::ToUTF8String(*it);
565 if (viewMode == VIEWMODE_TYPE_FULLSCREEN) {
568 } else if (viewMode == VIEWMODE_TYPE_MAXIMIZED) {
573 m_windowData->setViewMode(fullscreen,
577 void WrtClient::backButtonCallback(void* data,
578 Evas_Object * /*obj*/,
579 void * /*event_info*/)
581 LogInfo("BackButtonCallback");
584 WrtClient* This = static_cast<WrtClient*>(data);
586 This->m_widget->Backward();
589 int WrtClient::appcoreLowMemoryCallback(void* /*data*/)
591 LogInfo("appcoreLowMemoryCallback");
592 //WrtClient* This = static_cast<WrtClient*>(data);
594 // TODO call RunnableWidgetObject API regarding low memory
595 // The API should be implemented
600 void WrtClient::connectElmCallback()
602 Assert(m_windowData);
604 if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
605 WidgetSettings widgetSettings;
606 m_dao->getWidgetSettings(widgetSettings);
607 WidgetSettingList settings(widgetSettings);
608 if (settings.getBackButtonPresence() == BackButton_Enable) {
609 m_windowData->addFloatBackButtonCallback(
611 &WrtClient::backButtonCallback,
615 WidgetSettingScreenLock rotationValue = settings.getRotationValue();
616 if (rotationValue == Screen_Portrait) {
617 elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
618 ewk_view_orientation_send(m_widget->GetCurrentWebview(), 0);
619 } else if (rotationValue == Screen_Landscape) {
620 elm_win_rotation_with_resize_set(m_windowData->m_win, 270);
621 ewk_view_orientation_send(m_widget->GetCurrentWebview(), 90);
623 elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
624 ewk_view_orientation_send(m_widget->GetCurrentWebview(), 0);
629 void WrtClient::setLayout(Evas_Object* newBuffer)
631 LogDebug("add new webkit buffer to window");
634 elm_object_part_content_set(m_windowData->m_user_layout,
638 evas_object_show(newBuffer);
641 void WrtClient::unsetLayout(Evas_Object* currentBuffer)
643 LogDebug("remove current webkit buffer from window");
644 Assert(currentBuffer);
645 evas_object_hide(currentBuffer);
647 elm_object_part_content_unset(m_windowData->m_user_layout,
648 ELM_SWALLOW_CONTENT);
651 void WrtClient::shutdownStep()
653 LogDebug("Closing Wrt connection ...");
655 if (m_widget && m_widgetState) {
656 m_widgetState = WidgetState_Stopped;
659 ewk_context_delete(s_ewk_context);
660 WRT::CoreModuleSingleton::Instance().Terminate();
663 m_initialized = false;
665 m_windowData.reset();
669 int WrtClient::languageChangedCallback(void *data)
671 LogDebug("Language Changed");
675 WrtClient* wrtClient = static_cast<WrtClient*>(data);
676 if (!(wrtClient->m_dao)) {
680 // reset function fetches system locales and recreates language tags
681 LanguageTagsProviderSingleton::Instance().resetLanguageTags();
682 // widget default locales are added to language tags below
683 DPL::OptionalString defloc = wrtClient->m_dao->getDefaultlocale();
684 if (!defloc.IsNull()) {
685 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
689 if (wrtClient->m_launched &&
690 wrtClient->m_widgetState != WidgetState_Stopped)
692 wrtClient->m_widget->ReloadStartPage();
697 void WrtClient::Quit()
700 DPL::Application::Quit();
706 UNHANDLED_EXCEPTION_HANDLER_BEGIN
708 ADD_PROFILING_POINT("main-entered", "point");
711 DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
713 // set evas backend type
714 if (!getenv("ELM_ENGINE")) {
715 if (!setenv("ELM_ENGINE", "gl", 1)) {
716 LogDebug("Enable backend");
719 LogDebug("ELM_ENGINE : " << getenv("ELM_ENGINE"));
723 setenv("COREGL_FASTPATH", "1", 1);
725 setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
726 setenv("CAIRO_GL_LAZY_FLUSHING", "yes", 1);
727 setenv("ELM_IMAGE_CACHE", "0", 1);
729 // This code is to fork a web process without exec.
730 std::string tizenId = WrtClient::getTizenIdFromArgument(argc, argv);
732 if (!tizenId.empty()) {
733 LogDebug("Launching by fork mode");
734 // Language env setup
735 appcore_set_i18n("wrt-client", NULL);
737 ewk_set_arguments(argc, argv);
738 setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
739 s_ewk_context = ewk_context_new_with_injected_bundle_path(
743 PluginModuleSupport::init(s_ewk_context, tizenId);
746 // Output on stdout will be flushed after every newline character,
747 // even if it is redirected to a pipe. This is useful for running
748 // from a script and parsing output.
749 // (Standard behavior of stdlib is to use full buffering when
750 // redirected to a pipe, which means even after an end of line
751 // the output may not be flushed).
754 WrtClient app(argc, argv);
756 ADD_PROFILING_POINT("Before appExec", "point");
757 int ret = app.Exec();
758 LogDebug("App returned: " << ret);
759 ret = app.getReturnStatus();
760 LogDebug("WrtClient returned: " << ret);
763 UNHANDLED_EXCEPTION_HANDLER_END