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"
20 #include <dpl/log/log.h>
21 #include <dpl/optional_typedefs.h>
22 #include <dpl/exception.h>
23 #include <common/application_data.h>
24 #include <core_module.h>
25 #include <localization_setting.h>
26 #include <widget_deserialize_model.h>
28 #include <dpl/localization/w3c_file_localization.h>
29 #include <dpl/localization/LanguageTagsProvider.h>
31 //W3C PACKAGING enviroment variable name
32 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
34 // window signal callback
35 const char *EDJE_SHOW_BACKWARD_SIGNAL = "show,backward,signal";
36 const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
37 const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized";
38 char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content";
39 const char* const BUNDLE_PATH = "/usr/lib/wrt-wk2-bundles/libwrt-wk2-bundle.so";
41 static Ewk_Context* s_ewk_context = NULL;
43 WrtClient::WrtClient(int argc, char **argv) :
44 Application(argc, argv, "wrt-client", false),
45 DPL::TaskDecl<WrtClient>(this),
47 m_initializing(false),
52 m_returnStatus(ReturnStatus::Succeeded),
53 m_widgetState(WidgetState::WidgetState_Stopped)
56 LogDebug("App Created");
59 WrtClient::~WrtClient()
61 LogDebug("App Finished");
64 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
66 return m_returnStatus;
69 void WrtClient::OnStop()
71 LogInfo("Stopping Dummy Client");
75 void WrtClient::OnCreate()
78 ADD_PROFILING_POINT("OnCreate callback", "point");
83 void WrtClient::OnResume()
85 if (m_widgetState != WidgetState_Suspended) {
86 LogWarning("Widget is not suspended, resuming was skipped");
90 m_widgetState = WidgetState_Running;
94 void WrtClient::OnPause()
98 if (m_widgetState != WidgetState_Running) {
99 LogWarning("Widget is not running to be suspended");
103 m_widgetState = WidgetState_Suspended;
106 void WrtClient::OnReset(bundle *b)
109 // bundle argument is freed after OnReset() is returned
110 // So bundle duplication is needed
111 ApplicationDataSingleton::Instance().setBundle(bundle_dup(b));
113 if (true == m_initializing) {
114 LogDebug("can not handle reset event");
117 if (true == m_launched) {
118 if (m_widgetState == WidgetState_Stopped) {
119 LogError("Widget is not running to be reset");
123 m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
124 m_widgetState = WidgetState_Running;
126 if (true == checkArgument())
137 void WrtClient::OnTerminate()
139 LogDebug("Wrt Shutdown now");
143 void WrtClient::showHelpAndQuit()
145 printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
147 "Mandatory arguments to long options are mandatory for short "
149 " -h, --help show this help\n"
151 "launch widget with given tizen ID\n"
153 "launch widget with given tizen ID\n"
159 bool WrtClient::checkArgument()
161 std::string tizenId = getTizenIdFromArgument(m_argc, m_argv);
168 LogDebug("Tizen id: " << m_tizenId);
173 std::string WrtClient::getTizenIdFromArgument(int argc, char **argv)
175 LogInfo("checkArgument");
176 std::string arg = argv[0];
182 if (arg.find("wrt-client") != std::string::npos) {
189 if (arg == "-h" || arg == "--help") {
191 } else if (arg == "-l" || arg == "--launch" ||
192 arg == "-t" || arg == "--tizen") {
201 // Launch widget based on application basename
202 size_t pos = arg.find_last_of('/');
204 if (pos != std::string::npos) {
205 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 bool developerMode = 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(s_ewk_context)) {
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) {
331 LogError("WAC test certified developer widget is needed for " <<
335 //TODO: WR-4660 (show popup about developer widget
337 LogInfo("POPUP: THIS IS TEST WIDGET!");
340 ADD_PROFILING_POINT("DeveloperModeCheck", "stop");
344 void WrtClient::loadFinishCallback(Evas_Object* webview)
346 ADD_PROFILING_POINT("loadFinishCallback", "start");
347 SDKDebugData* debug = new SDKDebugData;
348 debug->debugMode = m_debugMode;
349 debug->pid = new unsigned long(getpid());
351 LogInfo("Post result of launch");
353 // Start inspector server, if current mode is debugger mode.
354 // In the WK2 case, ewk_view_inspector_server_start should
355 // be called after WebProcess is created.
356 if (checkDebugMode(debug))
359 ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0);
360 if (debug->portnum == 0) {
361 LogWarning("Failed to get portnum");
363 LogInfo("Assigned port number for inspector : "
367 LogDebug("Debug mode is disabled");
370 //w3c packaging test debug (message on 4>)
371 const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE);
372 if(makeScreen != NULL && strcmp(makeScreen, "1") == 0)
374 FILE* doutput = fdopen(4, "w");
375 fprintf(doutput,"didFinishLoadForFrameCallback: ready\n");
380 LogDebug("Launch succesfull");
383 m_initializing = false;
385 ADD_PROFILING_POINT("loadFinishCallback", "stop");
386 printf("launched\n");
391 m_returnStatus = ReturnStatus::Failed;
393 DPL::Event::ControllerEventHandler<NextStepEvent>::
394 PostEvent(NextStepEvent());
399 LogDebug("Send RT signal to wrt-launcher(pid: " << m_sdkLauncherPid);
401 /* send real time signal with result to wrt-launcher */
403 LogDebug("userData->portnum : " << debug->portnum);
404 sv.sival_int = debug->portnum;
408 sigqueue(m_sdkLauncherPid, SIGRTMIN, sv);
411 ApplicationDataSingleton::Instance().freeBundle();
413 LogDebug("Cleaning wrtClient launch resources...");
418 void WrtClient::progressFinishCallback()
420 m_splashScreen->stopSplashScreen();
423 void WrtClient::webkitExitCallback()
425 LogDebug("window close called, terminating app");
426 SwitchToStep(&WrtClient::shutdownStep);
427 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
431 void WrtClient::webCrashCallback()
433 LogError("webProcess crashed");
434 SwitchToStep(&WrtClient::shutdownStep);
435 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
440 void WrtClient::launchStep()
442 ADD_PROFILING_POINT("launchStep", "start");
443 LogDebug("Launching widget ...");
445 ADD_PROFILING_POINT("getRunnableWidgetObject", "start");
446 m_widget = WRT::CoreModuleSingleton::Instance()
447 .getRunnableWidgetObject(m_tizenId);
448 ADD_PROFILING_POINT("getRunnableWidgetObject", "stop");
451 LogError("RunnableWidgetObject is NULL, stop launchStep");
452 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
457 if (m_widgetState == WidgetState_Running) {
458 LogWarning("Widget already running, stop launchStep");
459 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
464 if (m_widgetState == WidgetState_Authorizing) {
465 LogWarning("Widget already authorizing, stop launchStep");
466 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
471 m_dao.reset(new WrtDB::WidgetDAOReadOnly(DPL::FromASCIIString(m_tizenId)));
472 DPL::Optional<DPL::String> defloc = m_dao->getDefaultlocale();
475 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(*defloc);
478 // For localizationsetting not changed on widget running
479 //LocalizationSetting::SetLanguageChangedCallback(
480 // languageChangedCallback, this);
482 ADD_PROFILING_POINT("CreateWindow", "start");
483 m_windowData.reset(new WindowData(static_cast<unsigned long>(getpid())));
484 ADD_PROFILING_POINT("CreateWindow", "stop");
486 WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
487 ADD_PROFILING_POINT("Create splash screen", "start");
488 m_splashScreen.reset(
489 new SplashScreenSupport(m_windowData->m_win));
490 if (m_splashScreen->createSplashScreen(m_dao->getSplashImgSrc())) {
491 m_splashScreen->startSplashScreen();
492 cbs->progressFinish = DPL::MakeDelegate(this, &WrtClient::progressFinishCallback);
494 ADD_PROFILING_POINT("Create splash screen", "stop");
495 DPL::OptionalString startUrl = W3CFileLocalization::getStartFile(m_dao);
496 m_widget->PrepareView(DPL::ToUTF8String(*startUrl),
497 m_windowData->m_win);
498 //you can't show window with splash screen before PrepareView
499 //ewk_view_add_with_context() in viewLogic breaks window
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())
514 LogWarning("WAC Certificate failed, stop launchStep");
518 m_widgetState = WidgetState_Authorizing;
519 if (!m_widget->CheckBeforeLaunch()) {
520 LogError("CheckBeforeLaunch failed, stop launchStep");
521 DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
525 LogInfo("Widget launch accepted. Entering running state");
526 m_widgetState = WidgetState_Running;
528 cbs->loadFinish = DPL::MakeDelegate(this, &WrtClient::loadFinishCallback);
529 cbs->bufferSet = DPL::MakeDelegate(this, &WrtClient::setLayout);
530 cbs->bufferUnset = DPL::MakeDelegate(this, &WrtClient::unsetLayout);
531 cbs->webkitExit = DPL::MakeDelegate(this, &WrtClient::webkitExitCallback);
532 cbs->webCrash = DPL::MakeDelegate(this, &WrtClient::webCrashCallback);
533 cbs->toggleFullscreen = DPL::MakeDelegate(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) {
610 LogDebug("add new webkit buffer to window");
613 elm_object_part_content_set(m_windowData->m_user_layout, ELM_SWALLOW_CONTENT, newBuffer);
615 evas_object_show(newBuffer);
618 void WrtClient::unsetLayout(Evas_Object* currentBuffer) {
619 LogDebug("remove current webkit buffer from window");
620 Assert(currentBuffer);
621 evas_object_hide(currentBuffer);
623 elm_object_part_content_unset(m_windowData->m_user_layout, ELM_SWALLOW_CONTENT);
626 void WrtClient::shutdownStep()
628 LogDebug("Closing Wrt connection ...");
629 if (m_initialized && m_widget) {
630 m_widgetState = WidgetState_Stopped;
633 m_windowData.reset();
634 WRT::CoreModuleSingleton::Instance().Terminate();
635 m_initialized = false;
640 int WrtClient::languageChangedCallback(void *data)
642 LogDebug("Language Changed");
645 WrtClient* wrtClient = static_cast<WrtClient*>(data);
646 if(!(wrtClient->m_dao))
649 // reset function fetches system locales and recreates language tags
650 LanguageTagsProviderSingleton::Instance().resetLanguageTags();
651 // widget default locales are added to language tags below
652 DPL::OptionalString defloc = wrtClient->m_dao->getDefaultlocale();
655 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(*defloc);
658 if (wrtClient->m_launched &&
659 wrtClient->m_widgetState != WidgetState_Stopped) {
660 wrtClient->m_widget->ReloadStartPage();
665 void WrtClient::Quit()
668 DPL::Application::Quit();
674 UNHANDLED_EXCEPTION_HANDLER_BEGIN
676 ADD_PROFILING_POINT("main-entered", "point");
679 DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
681 // This code is to fork a web process without exec.
682 std::string tizenId = WrtClient::getTizenIdFromArgument(argc, argv);
684 if (!tizenId.empty())
686 LogDebug("Launching by fork mode");
688 ewk_set_arguments(argc, argv);
689 setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
690 s_ewk_context = ewk_context_new_with_injected_bundle_path(BUNDLE_PATH);
693 // Output on stdout will be flushed after every newline character,
694 // even if it is redirected to a pipe. This is useful for running
695 // from a script and parsing output.
696 // (Standard behavior of stdlib is to use full buffering when
697 // redirected to a pipe, which means even after an end of line
698 // the output may not be flushed).
701 // set evas backend type
702 if (!getenv("ELM_ENGINE")) {
703 if (!setenv("ELM_ENGINE", "gl", 1)) {
704 LogDebug("Enable backend");
708 LogDebug("ELM_ENGINE : " << getenv("ELM_ENGINE"));
712 setenv("COREGL_FASTPATH", "1", 1);
714 setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
715 setenv("CAIRO_GL_LAZY_FLUSHING", "yes", 1);
716 setenv("ELM_IMAGE_CACHE", "0", 1);
718 WrtClient app(argc, argv);
720 ADD_PROFILING_POINT("Before appExec", "point");
721 int ret = app.Exec();
722 LogDebug("App returned: " << ret);
723 ret = app.getReturnStatus();
724 LogDebug("WrtClient returned: " << ret);
727 UNHANDLED_EXCEPTION_HANDLER_END