X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fwrt-client%2Fwrt-client.cpp;h=188bf04ca18e472e1bb76fcc3d15cb3efd32eb9e;hb=4c33c56a40de04d4edd713f723e5716cb7a771f0;hp=1e211bc716cc7647c20b27a268e20d9cc674f9bc;hpb=d603917882d8588a4d6ec4c8a69b125eb47bb055;p=platform%2Fframework%2Fweb%2Fwrt.git diff --git a/src/wrt-client/wrt-client.cpp b/src/wrt-client/wrt-client.cpp old mode 100755 new mode 100644 index 1e211bc..188bf04 --- a/src/wrt-client/wrt-client.cpp +++ b/src/wrt-client/wrt-client.cpp @@ -14,28 +14,62 @@ * limitations under the License. */ #include "wrt-client.h" +#include +#include +#include +#include +#include #include #include #include #include #include -#include +#include +#include #include -#include -#include #include #include #include #include #include +#include +#include +#include "auto_rotation_support.h" + +#include +#include + +#include "client_command_line_parser.h" +#include "client_ide_support.h" +#include "client_security_support.h" +#include "client_service_support.h" +#include "client_submode_support.h" //W3C PACKAGING enviroment variable name #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH" // window signal callback +const char *EDJE_SHOW_PROGRESS_SIGNAL = "show,progress,signal"; +const char *EDJE_HIDE_PROGRESS_SIGNAL = "hide,progress,signal"; const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen"; const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized"; +const std::string VIEWMODE_TYPE_WINDOWED = "windowed"; char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content"; +const char* const BUNDLE_PATH = LIBDIR_PREFIX "/usr/lib/libwrt-injected-bundle.so"; +const char* const MESSAGE_NAME_INITIALIZE = "ToInjectedBundle::INIT"; +const unsigned int UID_ROOT = 0; + +// process pool +const char* const DUMMY_PROCESS_PATH = "/usr/bin/wrt_launchpad_daemon_candidate"; +static Ewk_Context* s_preparedEwkContext = NULL; +static WindowData* s_preparedWindowData = NULL; +static int app_argc = 0; +static char** app_argv = NULL; + +// env +const char* const HOME = "HOME"; +const char* const APP_HOME_PATH = "/opt/home/app"; +const char* const ROOT_HOME_PATH = "/opt/home/root"; WrtClient::WrtClient(int argc, char **argv) : Application(argc, argv, "wrt-client", false), @@ -43,11 +77,14 @@ WrtClient::WrtClient(int argc, char **argv) : m_launched(false), m_initializing(false), m_initialized(false), - m_sdkLauncherPid(0), m_debugMode(false), - m_debuggerPort(0), m_returnStatus(ReturnStatus::Succeeded), - m_widgetState(WidgetState::WidgetState_Stopped) + m_widgetState(WidgetState::WidgetState_Stopped), + m_initialViewMode(VIEWMODE_TYPE_MAXIMIZED), + m_currentViewMode(VIEWMODE_TYPE_MAXIMIZED), + m_isWebkitFullscreen(false), + m_isFullscreenByPlatform(false), + m_submodeSupport(new ClientModule::SubmodeSupport()) { Touch(); LogDebug("App Created"); @@ -65,17 +102,16 @@ WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const void WrtClient::OnStop() { - LogInfo("Stopping Dummy Client"); + LogDebug("Stopping Dummy Client"); } - void WrtClient::OnCreate() { - LogInfo("On Create"); + LogDebug("On Create"); ADD_PROFILING_POINT("OnCreate callback", "point"); + ewk_init(); } - void WrtClient::OnResume() { if (m_widgetState != WidgetState_Suspended) { @@ -83,19 +119,21 @@ void WrtClient::OnResume() return; } m_widget->Resume(); - evas_object_focus_set(m_widget->GetCurrentWebview(), EINA_TRUE); m_widgetState = WidgetState_Running; } - void WrtClient::OnPause() { if (m_widgetState != WidgetState_Running) { LogWarning("Widget is not running to be suspended"); return; } + if (m_submodeSupport->isNeedTerminateOnSuspend()) { + LogDebug("Current mode cannot support suspend"); + elm_exit(); + return; + } m_widget->Suspend(); - evas_object_focus_set(m_widget->GetCurrentWebview(), EINA_FALSE); m_widgetState = WidgetState_Suspended; } @@ -105,6 +143,7 @@ void WrtClient::OnReset(bundle *b) // bundle argument is freed after OnReset() is returned // So bundle duplication is needed ApplicationDataSingleton::Instance().setBundle(bundle_dup(b)); + ApplicationDataSingleton::Instance().setEncodedBundle(b); if (true == m_initializing) { LogDebug("can not handle reset event"); @@ -116,19 +155,23 @@ void WrtClient::OnReset(bundle *b) return; } m_widget->Reset(); - elm_win_raise(m_windowData->m_win); - evas_object_focus_set(m_widget->GetCurrentWebview(), EINA_TRUE); m_widgetState = WidgetState_Running; } else { - if (true == checkArgument()) - { - setStep(); - } - else - { + m_tizenId = + ClientModule::CommandLineParser::getTizenId(m_argc, m_argv); + if (m_tizenId.empty()) { showHelpAndQuit(); + } else { + setDebugMode(b); + setStep(); } } + + // low memory callback set + appcore_set_event_callback( + APPCORE_EVENT_LOW_MEMORY, + WrtClient::appcoreLowMemoryCallback, + this); } void WrtClient::OnTerminate() @@ -153,59 +196,11 @@ void WrtClient::showHelpAndQuit() Quit(); } -bool WrtClient::checkArgument() -{ - LogInfo("checkArgument"); - - std::string arg = m_argv[0]; - - if (arg.empty()) { - return false; - } - - if (arg.find("wrt-client") != std::string::npos) - { - if (m_argc <= 1) { - return false; - } - - arg = m_argv[1]; - - if (arg == "-h" || arg == "--help") { - // Just show help - return false; - } else if (arg == "-l" || arg == "--launch" || - arg == "-t" || arg == "--tizen") { - if (m_argc != 3) { - return false; - } - m_tizenId = std::string(m_argv[2]); - } else { - return false; - } - } else { - size_t pos = arg.find_last_of('/'); - - if (pos != std::string::npos) { - arg = arg.erase(0, pos + 1); - } - - // Launch widget based on application basename - m_tizenId = arg; - LogDebug("Tizen id: " << m_tizenId); - } - - return true; -} - void WrtClient::setStep() { - LogInfo("setStep"); + LogDebug("setStep"); AddStep(&WrtClient::initStep); - - setSdkLauncherDebugData(); - AddStep(&WrtClient::launchStep); AddStep(&WrtClient::shutdownStep); @@ -214,61 +209,10 @@ void WrtClient::setStep() DPL::Event::ControllerEventHandler::PostEvent(NextStepEvent()); } -void WrtClient::setSdkLauncherDebugData() +void WrtClient::setDebugMode(bundle* b) { - LogDebug("setSdkLauncherDebugData"); - - /* check bundle from sdk launcher */ - bundle *bundleFromSdkLauncher; - bundleFromSdkLauncher = bundle_import_from_argv(m_argc, m_argv); - const char *bundle_debug = bundle_get_val(bundleFromSdkLauncher, "debug"); - const char *bundle_pid = bundle_get_val(bundleFromSdkLauncher, "pid"); - if (bundle_debug != NULL && bundle_pid != NULL) { - if (strcmp(bundle_debug, "true") == 0) { - m_debugMode = true; - m_sdkLauncherPid = atoi(bundle_pid); - } else { - m_debugMode = false; - } - } - bundle_free(bundleFromSdkLauncher); -} - -bool WrtClient::checkDebugMode(SDKDebugData* debugData) -{ - LogError("Checking for debug mode"); - Assert(m_dao); - - bool debugMode = debugData->debugMode; - - LogInfo("[DEBUG_MODE] Widget is launched in " << - (debugMode ? "DEBUG" : "RETAIL") << - " mode."); - - if (debugMode == true) { - // In WAC widget, only test widgets can use web inspector. - // In TIZEN widget, - // every launched widgets as debug mode can use it. - if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_WAC20) - { - bool developerMode = - GlobalLogicSingleton::Instance().GetGlobalModel() - ->DeveloperMode.Get(); - //This code will be activated - //after WAC test certificate is used by SDK - //bool isTestWidget = view->m_widgetModel->IsTestWidget.Get(); - //if(!isTestWidget) - //{ - // LogInfo("This is not WAC Test Widget"); - // break; - //} - if (!developerMode) { - LogInfo("This is not WAC Developer Mode"); - debugMode = false; - } - } - } - return debugMode; + m_debugMode = ClientModule::IDESupport::getDebugMode(b); + LogDebug("debug mode : " << m_debugMode); } void WrtClient::OnEventReceived(const NextStepEvent& /*event*/) @@ -287,86 +231,30 @@ void WrtClient::initStep() SwitchToStep(&WrtClient::shutdownStep); } - // ecore_event_jobs are processed sequentially without concession to - // other type events. To give a chance of execute to other events, - // ecore_timer_add was used. - DPL::Event::ControllerEventHandler::PostTimedEvent( - NextStepEvent(),0.001); -} - -bool WrtClient::checkWACTestCertififedWidget() -{ - // WAC Waikiki Beta Release Core Specification: Widget Runtime - // 10 Dec 2010 - // - // WR-4710 The WRT MUST enable debug functions only for WAC test widgets - // i.e. the functions must not be usable for normal WAC widgets, even when - // a WAC test widget is executing. - ADD_PROFILING_POINT("DeveloperModeCheck", "start"); - Assert(!!m_dao); - // WAC test widget - // A widget signed with a WAC-issued test certificate as described in - // Developer Mode. - - bool developerWidget = m_dao->isTestWidget(); - bool developerMode = - GlobalLogicSingleton::Instance().GetGlobalModel()->DeveloperMode.Get(); - - LogDebug("Is WAC test widget: " << developerWidget); - LogDebug("Is developer Mode: " << developerMode); - - if (developerWidget) { - if(!developerMode) - { - LogError("WAC test certified developer widget is needed for " << - "developer mode"); - return false; - }else{ - //TODO: WR-4660 (show popup about developer widget - // during launch - LogInfo("POPUP: THIS IS TEST WIDGET!"); - } - } - ADD_PROFILING_POINT("DeveloperModeCheck", "stop"); - return true; + DPL::Event::ControllerEventHandler::PostEvent(NextStepEvent()); } -void WrtClient::loadFinishCallback(bool success) +void WrtClient::loadFinishCallback(Evas_Object* webview) { ADD_PROFILING_POINT("loadFinishCallback", "start"); - SDKDebugData* debug = new SDKDebugData; - debug->debugMode = m_debugMode; - debug->pid = new unsigned long(getpid()); - - LogInfo("Post result of launch"); - // Start inspector server, if current mode is debugger mode. - // In the WK2 case, ewk_view_inspector_server_start should - // be called after WebProcess is created. - if (checkDebugMode(debug)) + // Splash screen + if (m_splashScreen && m_splashScreen->isShowing()) { - debug->portnum = - ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0); - if (debug->portnum == 0) { - LogWarning("Failed to get portnum"); - } else { - LogInfo("Assigned port number for inspector : " - << debug->portnum); - } - } else { - LogDebug("Debug mode is disabled"); + m_splashScreen->stopSplashScreenBuffered(); } + LogDebug("Post result of launch"); + //w3c packaging test debug (message on 4>) const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE); - if(makeScreen != NULL && strcmp(makeScreen, "1") == 0) - { + if (makeScreen != NULL && strcmp(makeScreen, "1") == 0) { FILE* doutput = fdopen(4, "w"); - fprintf(doutput,"didFinishLoadForFrameCallback: ready\n"); + fprintf(doutput, "didFinishLoadForFrameCallback: ready\n"); fclose(doutput); } - if (success) { + if (webview) { LogDebug("Launch succesfull"); m_launched = true; @@ -381,45 +269,71 @@ void WrtClient::loadFinishCallback(bool success) m_returnStatus = ReturnStatus::Failed; //shutdownStep DPL::Event::ControllerEventHandler:: - PostEvent(NextStepEvent()); + PostEvent(NextStepEvent()); } - if(debug->debugMode) - { - LogDebug("Send RT signal to wrt-launcher(pid: " - << m_sdkLauncherPid << ", status: " << success); - union sigval sv; - /* send real time signal with result to wrt-launcher */ - if(success) - { - LogDebug("userData->portnum : " << debug->portnum); - sv.sival_int = debug->portnum; - } - else - { - sv.sival_int = -1; + if (m_debugMode) { + unsigned int portNum = + ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0); + LogDebug("Port for inspector : " << portNum); + bool ret = ClientModule::IDESupport::sendReply( + ApplicationDataSingleton::Instance().getBundle(), + portNum); + if (!ret) { + LogWarning("Fail to send reply"); } - sigqueue(m_sdkLauncherPid, SIGRTMIN, sv); } ApplicationDataSingleton::Instance().freeBundle(); +} - LogDebug("Cleaning wrtClient launch resources..."); - delete debug->pid; - delete debug; +void WrtClient::resetCallback(bool result) +{ + if (!result) { + LogDebug("Fail to handle reset event"); + // free bundle data + ApplicationDataSingleton::Instance().freeBundle(); + } +} + +void WrtClient::progressStartedCallback() +{ + if (m_settingList->getProgressBarPresence() == ProgressBar_Enable || + m_currentViewMode == VIEWMODE_TYPE_WINDOWED) + { + m_windowData->signalEmit(Layer::MAIN_LAYOUT, + EDJE_SHOW_PROGRESS_SIGNAL, + ""); + m_windowData->updateProgress(0); + } +} + +void WrtClient::loadProgressCallback(Evas_Object* /*webview*/, double value) +{ + if (m_settingList->getProgressBarPresence() == ProgressBar_Enable || + m_currentViewMode == VIEWMODE_TYPE_WINDOWED) + { + m_windowData->updateProgress(value); + } } void WrtClient::progressFinishCallback() { - m_splashScreen->stopSplashScreen(); + if (m_settingList->getProgressBarPresence() == ProgressBar_Enable || + m_currentViewMode == VIEWMODE_TYPE_WINDOWED) + { + m_windowData->signalEmit(Layer::MAIN_LAYOUT, + EDJE_HIDE_PROGRESS_SIGNAL, + ""); + } } -void WrtClient::windowCloseCallback() +void WrtClient::webkitExitCallback() { LogDebug("window close called, terminating app"); SwitchToStep(&WrtClient::shutdownStep); DPL::Event::ControllerEventHandler::PostEvent( - NextStepEvent()); + NextStepEvent()); } void WrtClient::webCrashCallback() @@ -427,9 +341,29 @@ void WrtClient::webCrashCallback() LogError("webProcess crashed"); SwitchToStep(&WrtClient::shutdownStep); DPL::Event::ControllerEventHandler::PostEvent( - NextStepEvent()); + NextStepEvent()); +} + +void WrtClient::enterFullscreenCallback(Evas_Object* /*obj*/, + bool isFullscreenByPlatform) +{ + // enter fullscreen + m_windowData->toggleFullscreen(true); + m_currentViewMode = VIEWMODE_TYPE_FULLSCREEN; + m_isWebkitFullscreen = true; + if (isFullscreenByPlatform) { + m_isFullscreenByPlatform = true; + } } +void WrtClient::exitFullscreenCallback(Evas_Object* /*obj*/) +{ + // exit fullscreen + m_windowData->toggleFullscreen(false); + m_currentViewMode = m_initialViewMode; + m_isWebkitFullscreen = false; + m_isFullscreenByPlatform = false; +} void WrtClient::launchStep() { @@ -438,314 +372,767 @@ void WrtClient::launchStep() ADD_PROFILING_POINT("getRunnableWidgetObject", "start"); m_widget = WRT::CoreModuleSingleton::Instance() - .getRunnableWidgetObject(m_tizenId); + .getRunnableWidgetObject(m_tizenId); ADD_PROFILING_POINT("getRunnableWidgetObject", "stop"); if (!m_widget) { LogError("RunnableWidgetObject is NULL, stop launchStep"); DPL::Event::ControllerEventHandler::PostEvent( - NextStepEvent()); + NextStepEvent()); return; } if (m_widgetState == WidgetState_Running) { LogWarning("Widget already running, stop launchStep"); DPL::Event::ControllerEventHandler::PostEvent( - NextStepEvent()); + NextStepEvent()); return; } if (m_widgetState == WidgetState_Authorizing) { LogWarning("Widget already authorizing, stop launchStep"); DPL::Event::ControllerEventHandler::PostEvent( - NextStepEvent()); + NextStepEvent()); return; } - ADD_PROFILING_POINT("localizeWidgetModel", "start"); m_dao.reset(new WrtDB::WidgetDAOReadOnly(DPL::FromASCIIString(m_tizenId))); - Domain::localizeWidgetModel(m_dao->getDefaultlocale()); - ADD_PROFILING_POINT("localizeWidgetModel", "stop"); + WrtDB::WidgetSettings widgetSettings; + m_dao->getWidgetSettings(widgetSettings); + m_settingList.reset(new WidgetSettingList(widgetSettings)); + m_submodeSupport->initialize(DPL::FromASCIIString(m_tizenId)); + + DPL::Optional defloc = m_dao->getDefaultlocale(); + if (!defloc.IsNull()) { + LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales( + *defloc); + } + + setInitialViewMode(); + + /* remove language change callback */ + /* LocalizationSetting::SetLanguageChangedCallback( languageChangedCallback, this); + */ ADD_PROFILING_POINT("CreateWindow", "start"); - m_windowData.reset(new WindowData(static_cast(getpid()))); + if (s_preparedWindowData == NULL) { + m_windowData.reset(new WindowData(static_cast(getpid()), true)); + } else { + m_windowData.reset(s_preparedWindowData); + s_preparedWindowData = NULL; + } ADD_PROFILING_POINT("CreateWindow", "stop"); + if (!m_windowData->initScreenReaderSupport( + m_settingList->getAccessibility() == Accessibility_Enable)) + { + LogWarning("Fail to set screen reader support set"); + } + + // rotate window to initial value + setWindowInitialOrientation(); + setCtxpopupItem(); WRT::UserDelegatesPtr cbs(new WRT::UserDelegates); + ADD_PROFILING_POINT("Create splash screen", "start"); - m_splashScreen.reset( - new SplashScreenSupport(m_windowData->m_win)); - if (m_splashScreen->createSplashScreen(m_dao->getSplashImgSrc())) { + DPL::OptionalString splashImgSrc = m_dao->getSplashImgSrc(); + if (!splashImgSrc.IsNull()) + { + m_splashScreen.reset( + new SplashScreenSupport( + m_windowData->getEvasObject(Layer::WINDOW), + (DPL::ToUTF8String(*splashImgSrc)).c_str(), + m_currentViewMode != VIEWMODE_TYPE_FULLSCREEN, + m_settingList->getRotationValue() == Screen_Landscape)); m_splashScreen->startSplashScreen(); - cbs->progressFinish = DPL::MakeDelegate(this, &WrtClient::progressFinishCallback); } ADD_PROFILING_POINT("Create splash screen", "stop"); + DPL::OptionalString startUrl = W3CFileLocalization::getStartFile(m_dao); - m_widget->PrepareView(DPL::ToUTF8String(*startUrl), - m_windowData->m_win); + if (!m_widget->PrepareView( + DPL::ToUTF8String(*startUrl), + m_windowData->getEvasObject(Layer::WINDOW), + s_preparedEwkContext)) + { + DPL::Event::ControllerEventHandler::PostEvent( + NextStepEvent()); + return; + } + // send rotate information to ewk + setEwkInitialOrientation(); + //you can't show window with splash screen before PrepareView //ewk_view_add_with_context() in viewLogic breaks window - evas_object_show(m_windowData->m_win); - initializeWindowModes(); - connectElmCallback(); + m_windowData->init(); + m_windowData->postInit(); + +#if X11 + // sub-mode support + if (m_submodeSupport->isInlineMode()) { + if (m_submodeSupport->transientWindow( + elm_win_xwindow_get( + m_windowData->getEvasObject(Layer::WINDOW)))) + { + LogDebug("Success to set submode"); + } else { + LogWarning("Fail to set submode"); + } + } +#endif + m_windowData->smartCallbackAdd(Layer::FOCUS, + "focused", + focusedCallback, + this); + m_windowData->smartCallbackAdd(Layer::FOCUS, + "unfocused", + unfocusedCallback, + this); - if (!checkWACTestCertififedWidget()) - { - LogWarning("WAC Certificate failed, stop launchStep"); - return; + WrtDB::WidgetLocalizedInfo localizedInfo = + W3CFileLocalization::getLocalizedInfo(m_dao); + std::string name = ""; + if (!(localizedInfo.name.IsNull())) { + name = DPL::ToUTF8String(*(localizedInfo.name)); } + elm_win_title_set(m_windowData->getEvasObject(Layer::WINDOW), + name.c_str()); + + // window show + evas_object_show(m_windowData->getEvasObject(Layer::WINDOW)); + + initializeWindowModes(); m_widgetState = WidgetState_Authorizing; if (!m_widget->CheckBeforeLaunch()) { LogError("CheckBeforeLaunch failed, stop launchStep"); DPL::Event::ControllerEventHandler::PostEvent( - NextStepEvent()); + NextStepEvent()); return; } - LogInfo("Widget launch accepted. Entering running state"); + LogDebug("Widget launch accepted. Entering running state"); m_widgetState = WidgetState_Running; + cbs->progressStarted = DPL::MakeDelegate(this, &WrtClient::progressStartedCallback); + cbs->progress = DPL::MakeDelegate(this, &WrtClient::loadProgressCallback); + cbs->progressFinish = DPL::MakeDelegate(this, &WrtClient::progressFinishCallback); cbs->loadFinish = DPL::MakeDelegate(this, &WrtClient::loadFinishCallback); + cbs->reset = DPL::MakeDelegate(this, &WrtClient::resetCallback); cbs->bufferSet = DPL::MakeDelegate(this, &WrtClient::setLayout); cbs->bufferUnset = DPL::MakeDelegate(this, &WrtClient::unsetLayout); - cbs->windowClose = DPL::MakeDelegate(this, &WrtClient::windowCloseCallback); + cbs->webkitExit = DPL::MakeDelegate(this, &WrtClient::webkitExitCallback); cbs->webCrash = DPL::MakeDelegate(this, &WrtClient::webCrashCallback); - cbs->toggleFullscreen = DPL::MakeDelegate(m_windowData.get(), &WindowData::toggleFullscreen); + cbs->enterFullscreen = DPL::MakeDelegate(this, &WrtClient::enterFullscreenCallback); + cbs->exitFullscreen = DPL::MakeDelegate(this, &WrtClient::exitFullscreenCallback); + cbs->setOrientation = DPL::MakeDelegate(this, &WrtClient::setWindowOrientation); + cbs->hwkey = DPL::MakeDelegate(this, &WrtClient::hwkeyCallback); m_widget->SetUserDelegates(cbs); m_widget->Show(); + ADD_PROFILING_POINT("launchStep", "stop"); } void WrtClient::initializeWindowModes() { Assert(m_windowData); - Assert(m_dao); - auto windowModes = m_dao->getWindowModes(); - bool fullscreen = false; - FOREACH(it, windowModes) - { - std::string viewMode = DPL::ToUTF8String(*it); - if (viewMode == VIEWMODE_TYPE_FULLSCREEN) { - fullscreen = true; - break; - } else if (viewMode == VIEWMODE_TYPE_MAXIMIZED) { - break; - } - } - bool indicator = true; - if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) { - WidgetSettings widgetSettings; - m_dao->getWidgetSettings(widgetSettings); - WidgetSettingList settings(widgetSettings); - indicator = (settings.getIndicatorPresence() - == Indicator_Enable); - } + bool backbutton = + (m_settingList->getBackButtonPresence() == BackButton_Enable || + m_currentViewMode == VIEWMODE_TYPE_WINDOWED); + m_windowData->setViewMode(m_currentViewMode == VIEWMODE_TYPE_FULLSCREEN, + backbutton); +} - WrtDB::WidgetLocalizedInfo localizedInfo = - W3CFileLocalization::getLocalizedInfo(m_dao); - std::string name = ""; - if (!(localizedInfo.name.IsNull())) { - name = DPL::ToUTF8String(*(localizedInfo.name)); - } - LogInfo("initializeWindowModes " << m_debugMode); +Eina_Bool WrtClient::naviframeBackButtonCallback(void* data, + Elm_Object_Item* /*it*/) +{ + LogDebug("BackButtonCallback"); + Assert(data); - if(m_debugMode) { - m_windowData->m_debugMode = TRUE; - } - else { - m_windowData->m_debugMode = FALSE; - } + WrtClient* This = static_cast(data); + This->m_widget->Backward(); + return EINA_FALSE; +} - WindowData::CtxMenuItems ctxMenuItems; +int WrtClient::appcoreLowMemoryCallback(void* /*data*/) +{ + LogDebug("appcoreLowMemoryCallback"); + //WrtClient* This = static_cast(data); - WindowData::CtxMenuItem ctxMenuBackword; - ctxMenuBackword.label = WRT_OPTION_LABEL_BACKWARD; - ctxMenuBackword.icon = WRT_OPTION_ICON_BACKWARD; - ctxMenuBackword.callback = backwardCallback; - ctxMenuBackword.data = this; - ctxMenuItems.push_back(ctxMenuBackword); + // TODO call RunnableWidgetObject API regarding low memory + // The API should be implemented - WindowData::CtxMenuItem ctxMenuReload; - ctxMenuReload.label = WRT_OPTION_LABEL_RELOAD; - ctxMenuReload.icon = WRT_OPTION_ICON_RELOAD; - ctxMenuReload.callback = reloadCallback; - ctxMenuReload.data = this; - ctxMenuItems.push_back(ctxMenuReload); + // temporary solution because we have no way to get ewk_context from runnable object. + if (s_preparedEwkContext) + { + ewk_context_cache_clear(s_preparedEwkContext); + ewk_context_notify_low_memory(s_preparedEwkContext); + } - WindowData::CtxMenuItem ctxMenuForward; - ctxMenuForward.label = WRT_OPTION_LABEL_FORWARD; - ctxMenuForward.icon = WRT_OPTION_ICON_FORWARD; - ctxMenuForward.callback = forwardCallback; - ctxMenuForward.data = this; - ctxMenuItems.push_back(ctxMenuForward); + return 0; +} - m_windowData->setViewMode(fullscreen, - ctxMenuItems); +void WrtClient::setInitialViewMode(void) +{ + Assert(m_dao); + WrtDB::WindowModeList windowModes = m_dao->getWindowModes(); + FOREACH(it, windowModes) { + std::string viewMode = DPL::ToUTF8String(*it); + switch(viewMode[0]) { + case 'f': + if (viewMode == VIEWMODE_TYPE_FULLSCREEN) { + m_initialViewMode = viewMode; + m_currentViewMode = m_initialViewMode; + break; + } + break; + case 'm': + if (viewMode == VIEWMODE_TYPE_MAXIMIZED) { + m_initialViewMode = viewMode; + m_currentViewMode = m_initialViewMode; + break; + } + break; + case 'w': + if (viewMode == VIEWMODE_TYPE_WINDOWED) { + m_initialViewMode = viewMode; + m_currentViewMode = m_initialViewMode; + break; + } + break; + default: + break; + } + } } -void WrtClient::backButtonCallback(void* data, - Evas_Object * /*obj*/, - void * /*event_info*/) +void WrtClient::setWindowInitialOrientation(void) { - LogInfo("BackButtonCallback"); - Assert(data); + Assert(m_windowData); + Assert(m_dao); - WrtClient* This = static_cast(data); + WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue(); + if (rotationValue == Screen_Portrait) { + setWindowOrientation(OrientationAngle::Window::Portrait::PRIMARY); + } else if (rotationValue == Screen_Landscape) { + setWindowOrientation(OrientationAngle::Window::Landscape::PRIMARY); + } else if (rotationValue == Screen_AutoRotation) { + if (!AutoRotationSupport::setAutoRotation( + m_windowData->getEvasObject(Layer::WINDOW), + autoRotationCallback, + this)) + { + LogError("Fail to set auto rotation"); + } + } else { + setWindowOrientation(OrientationAngle::Window::Portrait::PRIMARY); + } +} - This->m_widget->Backward(); +void WrtClient::setWindowOrientation(int angle) +{ + Assert(m_windowData); + m_windowData->setOrientation(angle); } -void WrtClient::backwardCallback(void *data, - Evas_Object */*obj*/, - void */*event_info*/) +void WrtClient::unsetWindowOrientation(void) { - LogInfo("BackButtonCallback"); - Assert(data); + Assert(m_windowData); + Assert(m_dao); - WrtClient* This = static_cast(data); + WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue(); + if (rotationValue == Screen_AutoRotation) { + AutoRotationSupport::unsetAutoRotation( + m_windowData->getEvasObject(Layer::WINDOW), + autoRotationCallback); + } +} - This->m_widget->Backward(); - This->m_windowData->initFullViewMode(); +void WrtClient::setEwkInitialOrientation(void) +{ + Assert(m_widget); + Assert(m_dao); + + WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue(); + if (rotationValue == Screen_Portrait) { + ewk_view_orientation_send( + m_widget->GetCurrentWebview(), + OrientationAngle::W3C::Portrait::PRIMARY); + } else if (rotationValue == Screen_Landscape) { + ewk_view_orientation_send( + m_widget->GetCurrentWebview(), + OrientationAngle::W3C::Landscape::PRIMARY); + } else if (rotationValue == Screen_AutoRotation) { + ewk_view_orientation_send( + m_widget->GetCurrentWebview(), + OrientationAngle::W3C::Portrait::PRIMARY); + } else { + ewk_view_orientation_send( + m_widget->GetCurrentWebview(), + OrientationAngle::W3C::Portrait::PRIMARY); + } } -void WrtClient::reloadCallback(void *data, - Evas_Object */*obj*/, - void */*event_info*/) +void WrtClient::ExitCallback(void* data, + Evas_Object * /*obj*/, + void * /*event_info*/) { - LogInfo("reloadCallback"); + LogInfo("ExitCallback"); + Assert(data); WrtClient* This = static_cast(data); - This->m_widget->Reload(); - This->m_windowData->initFullViewMode(); + This->OnTerminate(); } -void WrtClient::forwardCallback(void *data, - Evas_Object */*obj*/, - void */*event_info*/) +void WrtClient::setCtxpopupItem(void) { - LogInfo("forwardCallback"); + WindowData::CtxpopupItemDataList data; + + // 1. share + WindowData::CtxpopupCallbackType shareCallback = + DPL::MakeDelegate(this, &WrtClient::ctxpopupShare); + WindowData::CtxpopupItemData shareData("Share", + std::string(), + shareCallback); + + // 2. reload + WindowData::CtxpopupCallbackType reloadCallback = + DPL::MakeDelegate(this, &WrtClient::ctxpopupReload); + WindowData::CtxpopupItemData reloadData("Reload", + std::string(), + reloadCallback); + + // 3. Open in browser + WindowData::CtxpopupCallbackType launchBrowserCallback = + DPL::MakeDelegate(this, &WrtClient::ctxpopupLaunchBrowser); + WindowData::CtxpopupItemData launchBrowserData("Open in browser", + std::string(), + launchBrowserCallback); + data.push_back(shareData); + data.push_back(reloadData); + data.push_back(launchBrowserData); + m_windowData->setCtxpopupItemData(data); +} - WrtClient* This = static_cast(data); +void WrtClient::ctxpopupShare(void) +{ + LogDebug("share"); +#ifdef X11 + const char* url = ewk_view_url_get(m_widget->GetCurrentWebview()); + if (!url) { + LogError("url is empty"); + return; + } + if (ClientModule::ServiceSupport::launchShareService( + elm_win_xwindow_get(m_windowData->getEvasObject(Layer::WINDOW)), + url)) + { + LogDebug("success"); + } else { + LogDebug("fail"); + } + evas_object_smart_callback_add(m_windowData->m_win, + "delete,request", + &WrtClient::ExitCallback, + this); +#endif +} - This->m_widget->Forward(); - This->m_windowData->initFullViewMode(); +void WrtClient::ctxpopupReload(void) +{ + LogDebug("reload"); + ewk_view_reload(m_widget->GetCurrentWebview()); } +void WrtClient::ctxpopupLaunchBrowser(void) +{ + LogDebug("launchBrowser"); +#ifdef X11 + const char* url = ewk_view_url_get(m_widget->GetCurrentWebview()); + if (!url) { + LogError("url is empty"); + return; + } + if (ClientModule::ServiceSupport::launchViewService( + elm_win_xwindow_get(m_windowData->getEvasObject(Layer::WINDOW)), + url)) + { + LogDebug("success"); + } else { + LogDebug("fail"); + } +#endif +} -void WrtClient::connectElmCallback() +void WrtClient::hwkeyCallback(const std::string& key) { - Assert(m_windowData); - Assert(m_dao); - if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) { - WidgetSettings widgetSettings; - m_dao->getWidgetSettings(widgetSettings); - WidgetSettingList settings(widgetSettings); - WidgetSettingScreenLock rotationValue = settings.getRotationValue(); - if (rotationValue == Screen_Portrait) { - elm_win_rotation_with_resize_set(m_windowData->m_win, 0); - } else if (rotationValue == Screen_Landscape) { - elm_win_rotation_with_resize_set(m_windowData->m_win, 270); - } else { - elm_win_rotation_with_resize_set(m_windowData->m_win, 0); + if (m_settingList->getBackButtonPresence() == BackButton_Enable + || m_currentViewMode == VIEWMODE_TYPE_WINDOWED) + { + // windowed UX - hosted application + if (key == KeyName::BACK) { + if (m_isWebkitFullscreen) { + // FIXME!!! This method has not yet landed in the tizen 3.0 + // webkit-efl source tree + //ewk_view_fullscreen_exit(m_widget->GetCurrentWebview()); + } else { + m_widget->Backward(); + } + } else if (key == KeyName::MENU) { + // UX isn't confirmed + // m_windowData->showCtxpopup(); + } + } else { + // packaged application + if (key == KeyName::BACK) { + if (m_isFullscreenByPlatform) { + // FIXME!!! This method has not yet landed in the tizen 3.0 + // webkit-efl source tree + //ewk_view_fullscreen_exit(m_widget->GetCurrentWebview()); + } } } } -void WrtClient::setLayout(Evas_Object* newBuffer) { +void WrtClient::setLayout(Evas_Object* webview) +{ LogDebug("add new webkit buffer to window"); - Assert(newBuffer); - - elm_object_part_content_set(m_windowData->m_user_layout, ELM_SWALLOW_CONTENT, newBuffer); - - evas_object_show(newBuffer); - evas_object_focus_set(newBuffer, EINA_TRUE); + Assert(webview); + m_windowData->setWebview(webview); + evas_object_show(webview); + evas_object_show(m_windowData->getEvasObject(Layer::WINDOW)); } -void WrtClient::unsetLayout(Evas_Object* currentBuffer) { +void WrtClient::unsetLayout(Evas_Object* webview) +{ LogDebug("remove current webkit buffer from window"); - Assert(currentBuffer); - evas_object_hide(currentBuffer); - - elm_object_part_content_unset(m_windowData->m_user_layout, ELM_SWALLOW_CONTENT); - + Assert(webview); + evas_object_hide(webview); + m_windowData->unsetWebview(); } void WrtClient::shutdownStep() { LogDebug("Closing Wrt connection ..."); - if (m_initialized && m_widget) { + + if (m_widget && m_widgetState) { m_widgetState = WidgetState_Stopped; m_widget->Hide(); + // AutoRotation, focusCallback use m_widget pointer internally. + // It must be unset before m_widget is released. + m_submodeSupport->deinitialize(); + unsetWindowOrientation(); + m_windowData->smartCallbackDel(Layer::FOCUS, + "focused", + focusedCallback); + m_windowData->smartCallbackDel(Layer::FOCUS, + "unfocused", + unfocusedCallback); m_widget.reset(); - m_windowData.reset(); + ewk_context_delete(s_preparedEwkContext); WRT::CoreModuleSingleton::Instance().Terminate(); + } + if (m_initialized) { m_initialized = false; } + m_windowData.reset(); Quit(); } +void WrtClient::autoRotationCallback(void* data, Evas_Object* obj, void* /*event*/) +{ + LogDebug("entered"); + + Assert(data); + Assert(obj); + + WrtClient* This = static_cast(data); + This->autoRotationSetOrientation(obj); +} + +void WrtClient::focusedCallback(void* data, + Evas_Object* /*obj*/, + void* /*eventInfo*/) +{ + LogDebug("entered"); + Assert(data); + WrtClient* This = static_cast(data); + elm_object_focus_set(This->m_widget->GetCurrentWebview(), EINA_TRUE); +} + +void WrtClient::unfocusedCallback(void* data, + Evas_Object* /*obj*/, + void* /*eventInfo*/) +{ + LogDebug("entered"); + Assert(data); + WrtClient* This = static_cast(data); + elm_object_focus_set(This->m_widget->GetCurrentWebview(), EINA_FALSE); +} + +void WrtClient::autoRotationSetOrientation(Evas_Object* obj) +{ + LogDebug("entered"); + Assert(obj); + + AutoRotationSupport::setOrientation(obj, m_widget->GetCurrentWebview(), + (m_splashScreen) ? m_splashScreen.get(): NULL); +} + int WrtClient::languageChangedCallback(void *data) { LogDebug("Language Changed"); + if (!data) { + return 0; + } WrtClient* wrtClient = static_cast(data); + if (!(wrtClient->m_dao)) { + return 0; + } - LanguageTags oldtags = LanguageTagsProviderSingleton::Instance().getLanguageTags(); // reset function fetches system locales and recreates language tags LanguageTagsProviderSingleton::Instance().resetLanguageTags(); - LanguageTags newtags = LanguageTagsProviderSingleton::Instance().getLanguageTags(); - - // check whether LanguageTags changed or not - if (oldtags != newtags) { - // update localized data - Domain::localizeWidgetModel(wrtClient->m_dao->getDefaultlocale()); + // widget default locales are added to language tags below + DPL::OptionalString defloc = wrtClient->m_dao->getDefaultlocale(); + if (!defloc.IsNull()) { + LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales( + *defloc); + } - if (true == wrtClient->m_launched && - wrtClient->m_widgetState != WidgetState_Stopped) { - wrtClient->m_widget->ReloadStartPage(); - } + if (wrtClient->m_launched && + wrtClient->m_widgetState != WidgetState_Stopped) + { + wrtClient->m_widget->ReloadStartPage(); } return 0; } -int main(int argc, - char *argv[]) +void WrtClient::Quit() +{ + ewk_shutdown(); + DPL::Application::Quit(); +} + +static Eina_Bool proces_pool_fd_handler(void* /*data*/, Ecore_Fd_Handler *handler) { - ADD_PROFILING_POINT("main-entered", "point"); + int fd = ecore_main_fd_handler_fd_get(handler); - // Output on stdout will be flushed after every newline character, - // even if it is redirected to a pipe. This is useful for running - // from a script and parsing output. - // (Standard behavior of stdlib is to use full buffering when - // redirected to a pipe, which means even after an end of line - // the output may not be flushed). - setlinebuf(stdout); + if (fd == -1) + { + LogDebug("ECORE_FD_GET"); + exit(-1); + } - // set evas backend type - if (!getenv("ELM_ENGINE")) { - if (setenv("ELM_ENGINE", "gl", 1)) { - LogDebug("Enable backend"); + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) + { + LogDebug("ECORE_FD_ERROR"); + close(fd); + exit(-1); + } + + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) + { + LogDebug("ECORE_FD_READ"); + { + app_pkt_t* pkt = (app_pkt_t*) malloc(sizeof(char) * AUL_SOCK_MAXBUFF); + memset(pkt, 0, AUL_SOCK_MAXBUFF); + + int recv_ret = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0); + close(fd); + + if (recv_ret == -1) + { + LogDebug("recv error!"); + free(pkt); + exit(-1); + } + + LogDebug("recv_ret : " << recv_ret << ", pkt->len : " << pkt->len); + ecore_main_fd_handler_del(handler); + process_pool_launchpad_main_loop(pkt, app_argv[0], &app_argc, &app_argv); + free(pkt); } + ecore_main_loop_quit(); } + + return ECORE_CALLBACK_CANCEL; +} + +static void vconf_changed_handler(keynode_t* /*key*/, void* /*data*/) +{ + LogDebug("VCONFKEY_LANGSET vconf-key was changed!"); + + // When system language is changed, the candidate process will be created again. + exit(-1); +} + +void set_env() +{ #ifndef TIZEN_PUBLIC setenv("COREGL_FASTPATH", "1", 1); #endif setenv("CAIRO_GL_COMPOSITOR", "msaa", 1); setenv("CAIRO_GL_LAZY_FLUSHING", "yes", 1); setenv("ELM_IMAGE_CACHE", "0", 1); +} + +int main(int argc, + char *argv[]) +{ + // process pool - store arg's value + app_argc = argc; + app_argv = argv; + +#ifndef X11 + // Mesa does a bad job detecting the correct EGL + // platform to use, and ends up assuming that the + // wrt-client is using X + setenv("EGL_PLATFORM", "wayland", 1); +#endif + + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + ADD_PROFILING_POINT("main-entered", "point"); + + // Set log tagging + DPL::Log::LogSystemSingleton::Instance().SetTag("WRT"); + + // Set environment variables + set_env(); + + if (argc > 1 && argv[1] != NULL && !strcmp(argv[1], "-d")) + { + LogDebug("Entered dummy process mode"); + sprintf(argv[0], "%s ", + DUMMY_PROCESS_PATH); + + // Set 'root' home directory + setenv(HOME, ROOT_HOME_PATH, 1); + + LogDebug("Prepare ewk_context"); + appcore_set_i18n("wrt-client", NULL); + ewk_set_arguments(argc, argv); + setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1); + s_preparedEwkContext = ewk_context_new_with_injected_bundle_path(BUNDLE_PATH); + + if (s_preparedEwkContext == NULL) + { + LogDebug("Creating webkit context was failed!"); + exit(-1); + } + + int client_fd = __connect_process_pool_server(); + + if (client_fd == -1) + { + LogDebug("Connecting process_pool_server was failed!"); + exit(-1); + } + + // register language changed callback + vconf_notify_key_changed(VCONFKEY_LANGSET, vconf_changed_handler, NULL); + + LogDebug("Prepare window_data"); + // Temporarily change HOME path to app + // This change is needed for getting elementary profile + // /opt/home/app/.elementary/config/mobile/base.cfg + const char* backupEnv = getenv(HOME); + if (!backupEnv) { + // If getenv return "NULL", set empty string + backupEnv = ""; + } + setenv(HOME, APP_HOME_PATH, 1); + LogDebug("elm_init()"); + elm_init(argc, argv); + setenv(HOME, backupEnv, 1); + + LogDebug("WindowData()"); + s_preparedWindowData = new WindowData(static_cast(getpid())); + + Ecore_Fd_Handler* fd_handler = ecore_main_fd_handler_add(client_fd, + (Ecore_Fd_Handler_Flags)(ECORE_FD_READ|ECORE_FD_ERROR), + proces_pool_fd_handler, NULL, NULL, NULL); + + if (fd_handler == NULL) + { + LogDebug("fd_handler is NULL"); + exit(-1); + } + + setpriority(PRIO_PROCESS, 0, 0); - // Set log tagging - DPL::Log::LogSystemSingleton::Instance().SetTag("WRT-CLIENT"); + LogDebug("ecore_main_loop_begin()"); + ecore_main_loop_begin(); + LogDebug("ecore_main_loop_begin()_end"); - WrtClient app(argc, argv); + // deregister language changed callback + vconf_ignore_key_changed(VCONFKEY_LANGSET, vconf_changed_handler); - ADD_PROFILING_POINT("Before appExec", "point"); - int ret = app.Exec(); - LogDebug("App returned: " << ret); - ret = app.getReturnStatus(); - LogDebug("WrtClient returned: " << ret); - return ret; + std::string tizenId = + ClientModule::CommandLineParser::getTizenId(argc, argv); + ewk_context_message_post_to_injected_bundle( + s_preparedEwkContext, + MESSAGE_NAME_INITIALIZE, + tizenId.c_str()); + + } + else + { + // This code is to fork a web process without exec. + std::string tizenId = + ClientModule::CommandLineParser::getTizenId(argc, argv); + + if (!tizenId.empty()) { + if (UID_ROOT == getuid()) { + // Drop root permission + // Only launch web application by console command case has root permission + if (!ClientModule::SecuritySupport::setAppPrivilege(tizenId)) { + LogError("Fail to set app privilege : [" << tizenId << "]"); + exit(-1); + } + } + + LogDebug("Launching by fork mode"); + // Language env setup + appcore_set_i18n("wrt-client", NULL); + ewk_set_arguments(argc, argv); + setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1); + s_preparedEwkContext = ewk_context_new_with_injected_bundle_path( + BUNDLE_PATH); + + if (s_preparedEwkContext == NULL) + { + LogDebug("Creating webkit context was failed!"); + Wrt::Popup::PopupInvoker().showInfo("Error", "Creating webkit context was failed.", "OK"); + exit(-1); + } + + // plugin init + ewk_context_message_post_to_injected_bundle( + s_preparedEwkContext, + MESSAGE_NAME_INITIALIZE, + tizenId.c_str()); + } + } + + // Output on stdout will be flushed after every newline character, + // even if it is redirected to a pipe. This is useful for running + // from a script and parsing output. + // (Standard behavior of stdlib is to use full buffering when + // redirected to a pipe, which means even after an end of line + // the output may not be flushed). + setlinebuf(stdout); + + WrtClient app(app_argc, app_argv); + + ADD_PROFILING_POINT("Before appExec", "point"); + int ret = app.Exec(); + LogDebug("App returned: " << ret); + ret = app.getReturnStatus(); + LogDebug("WrtClient returned: " << ret); + return ret; + } + UNHANDLED_EXCEPTION_HANDLER_END }