8cd235a58a0f577ca06d02102bbbd8740a22425f
[platform/framework/web/wrt.git] / src / wrt-client / wrt-client.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 #include "wrt-client.h"
17 #include <aul.h>
18 #include <sys/time.h>
19 #include <sys/resource.h>
20 #include <appcore-efl.h>
21 #include <appcore-common.h>
22 #include <cstdlib>
23 #include <cstdio>
24 #include <string>
25 #include <dpl/log/log.h>
26 #include <dpl/optional_typedefs.h>
27 #include <dpl/exception.h>
28 #include <application_data.h>
29 #include <core_module.h>
30 #include <localization_setting.h>
31 #include <widget_deserialize_model.h>
32 #include <EWebKit2.h>
33 #include <dpl/localization/w3c_file_localization.h>
34 #include <dpl/localization/LanguageTagsProvider.h>
35 #include <popup-runner/PopupInvoker.h>
36 #include <vconf.h>
37 #include "auto_rotation_support.h"
38
39 #include <process_pool.h>
40 #include <process_pool_launchpad_util.h>
41
42 #include "client_command_line_parser.h"
43 #include "client_ide_support.h"
44 #include "client_security_support.h"
45 #include "client_service_support.h"
46 #include "client_submode_support.h"
47
48 //W3C PACKAGING enviroment variable name
49 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
50
51 // window signal callback
52 const char *EDJE_SHOW_PROGRESS_SIGNAL = "show,progress,signal";
53 const char *EDJE_HIDE_PROGRESS_SIGNAL = "hide,progress,signal";
54 const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
55 const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized";
56 const std::string VIEWMODE_TYPE_WINDOWED = "windowed";
57 char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content";
58 const char* const BUNDLE_PATH = LIBDIR_PREFIX "/libwrt-injected-bundle.so";
59 const char* const MESSAGE_NAME_INITIALIZE = "ToInjectedBundle::INIT";
60 const unsigned int UID_ROOT = 0;
61
62 // process pool
63 const char* const DUMMY_PROCESS_PATH = "/usr/bin/wrt_launchpad_daemon_candidate";
64 static Ewk_Context* s_preparedEwkContext = NULL;
65 static WindowData*  s_preparedWindowData = NULL;
66 static int    app_argc = 0;
67 static char** app_argv = NULL;
68
69 // env
70 const char* const HOME = "HOME";
71 const char* const APP_HOME_PATH = "/opt/home/app";
72 const char* const ROOT_HOME_PATH = "/opt/home/root";
73
74 WrtClient::WrtClient(int argc, char **argv) :
75     Application(argc, argv, "wrt-client", false),
76     DPL::TaskDecl<WrtClient>(this),
77     m_launched(false),
78     m_initializing(false),
79     m_initialized(false),
80     m_debugMode(false),
81     m_returnStatus(ReturnStatus::Succeeded),
82     m_widgetState(WidgetState::WidgetState_Stopped),
83     m_initialViewMode(VIEWMODE_TYPE_MAXIMIZED),
84     m_currentViewMode(VIEWMODE_TYPE_MAXIMIZED),
85     m_isWebkitFullscreen(false),
86     m_submodeSupport(new ClientModule::SubmodeSupport())
87 {
88     Touch();
89     LogDebug("App Created");
90 }
91
92 WrtClient::~WrtClient()
93 {
94     LogDebug("App Finished");
95 }
96
97 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
98 {
99     return m_returnStatus;
100 }
101
102 void WrtClient::OnStop()
103 {
104     LogDebug("Stopping Dummy Client");
105 }
106
107 void WrtClient::OnCreate()
108 {
109     LogDebug("On Create");
110     ADD_PROFILING_POINT("OnCreate callback", "point");
111     ewk_init();
112 }
113
114 void WrtClient::OnResume()
115 {
116     if (m_widgetState != WidgetState_Suspended) {
117         LogWarning("Widget is not suspended, resuming was skipped");
118         return;
119     }
120     m_widget->Resume();
121     m_widgetState = WidgetState_Running;
122 }
123
124 void WrtClient::OnPause()
125 {
126     if (m_widgetState != WidgetState_Running) {
127         LogWarning("Widget is not running to be suspended");
128         return;
129     }
130     if (m_submodeSupport->isNeedTerminateOnSuspend()) {
131         LogDebug("Current mode cannot support suspend");
132         elm_exit();
133         return;
134     }
135     m_widget->Suspend();
136     m_widgetState = WidgetState_Suspended;
137 }
138
139 void WrtClient::OnReset(bundle *b)
140 {
141     LogDebug("OnReset");
142     // bundle argument is freed after OnReset() is returned
143     // So bundle duplication is needed
144     ApplicationDataSingleton::Instance().setBundle(bundle_dup(b));
145     ApplicationDataSingleton::Instance().setEncodedBundle(b);
146
147     if (true == m_initializing) {
148         LogDebug("can not handle reset event");
149         return;
150     }
151     if (true == m_launched) {
152         if (m_widgetState == WidgetState_Stopped) {
153             LogError("Widget is not running to be reset");
154             return;
155         }
156         m_widget->Reset();
157         m_widgetState = WidgetState_Running;
158     } else {
159         m_tizenId =
160             ClientModule::CommandLineParser::getTizenId(m_argc, m_argv);
161         if (m_tizenId.empty()) {
162             showHelpAndQuit();
163         } else {
164             setDebugMode(b);
165             setStep();
166         }
167     }
168
169     // low memory callback set
170     appcore_set_event_callback(
171             APPCORE_EVENT_LOW_MEMORY,
172             WrtClient::appcoreLowMemoryCallback,
173             this);
174 }
175
176 void WrtClient::OnTerminate()
177 {
178     LogDebug("Wrt Shutdown now");
179     shutdownStep();
180 }
181
182 void WrtClient::showHelpAndQuit()
183 {
184     printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
185            "launch widgets.\n"
186            "Mandatory arguments to long options are mandatory for short "
187            "options too.\n"
188            "  -h,    --help                                 show this help\n"
189            "  -l,    --launch                               "
190            "launch widget with given tizen ID\n"
191            "  -t,    --tizen                                "
192            "launch widget with given tizen ID\n"
193            "\n");
194
195     Quit();
196 }
197
198 void WrtClient::setStep()
199 {
200     LogDebug("setStep");
201
202     AddStep(&WrtClient::initStep);
203     AddStep(&WrtClient::launchStep);
204     AddStep(&WrtClient::shutdownStep);
205
206     m_initializing = true;
207
208     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
209 }
210
211 void WrtClient::setDebugMode(bundle* b)
212 {
213     m_debugMode = ClientModule::IDESupport::getDebugMode(b);
214     LogDebug("debug mode : " << m_debugMode);
215 }
216
217 void WrtClient::OnEventReceived(const NextStepEvent& /*event*/)
218 {
219     LogDebug("Executing next step");
220     NextStep();
221 }
222
223 void WrtClient::initStep()
224 {
225     LogDebug("");
226     if (WRT::CoreModuleSingleton::Instance().Init()) {
227         m_initialized = true;
228     } else {
229         m_returnStatus = ReturnStatus::Failed;
230         SwitchToStep(&WrtClient::shutdownStep);
231     }
232
233     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
234 }
235
236 void WrtClient::loadFinishCallback(Evas_Object* webview)
237 {
238     ADD_PROFILING_POINT("loadFinishCallback", "start");
239
240     // Splash screen
241     if (m_splashScreen && m_splashScreen->isShowing())
242     {
243         m_splashScreen->stopSplashScreenBuffered();
244     }
245
246     LogDebug("Post result of launch");
247
248     //w3c packaging test debug (message on 4>)
249     const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE);
250     if (makeScreen != NULL && strcmp(makeScreen, "1") == 0) {
251         FILE* doutput = fdopen(4, "w");
252         fprintf(doutput, "didFinishLoadForFrameCallback: ready\n");
253         fclose(doutput);
254     }
255
256     if (webview) {
257         LogDebug("Launch succesfull");
258
259         m_launched = true;
260         m_initializing = false;
261         setlinebuf(stdout);
262         ADD_PROFILING_POINT("loadFinishCallback", "stop");
263         printf("launched\n");
264         fflush(stdout);
265     } else {
266         printf("failed\n");
267
268         m_returnStatus = ReturnStatus::Failed;
269         //shutdownStep
270         DPL::Event::ControllerEventHandler<NextStepEvent>::
271             PostEvent(NextStepEvent());
272     }
273
274     if (m_debugMode) {
275         unsigned int portNum =
276             ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0);
277         LogDebug("Port for inspector : " << portNum);
278         bool ret = ClientModule::IDESupport::sendReply(
279                        ApplicationDataSingleton::Instance().getBundle(),
280                        portNum);
281         if (!ret) {
282             LogWarning("Fail to send reply");
283         }
284     }
285
286     ApplicationDataSingleton::Instance().freeBundle();
287 }
288
289 void WrtClient::resetCallback(bool result)
290 {
291     if (!result) {
292         LogDebug("Fail to handle reset event");
293         // free bundle data
294         ApplicationDataSingleton::Instance().freeBundle();
295     }
296 }
297
298 void WrtClient::progressStartedCallback()
299 {
300     if (m_settingList->getProgressBarPresence() == ProgressBar_Enable ||
301         m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
302     {
303         m_windowData->signalEmit(Layer::MAIN_LAYOUT,
304                                  EDJE_SHOW_PROGRESS_SIGNAL,
305                                  "");
306         m_windowData->updateProgress(0);
307     }
308 }
309
310 void WrtClient::loadProgressCallback(Evas_Object* /*webview*/, double value)
311 {
312     if (m_settingList->getProgressBarPresence() == ProgressBar_Enable ||
313         m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
314     {
315         m_windowData->updateProgress(value);
316     }
317 }
318
319 void WrtClient::progressFinishCallback()
320 {
321     if (m_settingList->getProgressBarPresence() == ProgressBar_Enable ||
322         m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
323     {
324         m_windowData->signalEmit(Layer::MAIN_LAYOUT,
325                                  EDJE_HIDE_PROGRESS_SIGNAL,
326                                  "");
327     }
328 }
329
330 void WrtClient::webkitExitCallback()
331 {
332     LogDebug("window close called, terminating app");
333     SwitchToStep(&WrtClient::shutdownStep);
334     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
335         NextStepEvent());
336 }
337
338 void WrtClient::webCrashCallback()
339 {
340     LogError("webProcess crashed");
341     SwitchToStep(&WrtClient::shutdownStep);
342     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
343         NextStepEvent());
344 }
345
346 void WrtClient::enterFullscreenCallback(Evas_Object* /*obj*/)
347 {
348     // enter fullscreen
349     m_windowData->toggleFullscreen(true);
350     m_currentViewMode = VIEWMODE_TYPE_FULLSCREEN;
351     m_isWebkitFullscreen = true;
352 }
353
354 void WrtClient::exitFullscreenCallback(Evas_Object* /*obj*/)
355 {
356     // exit fullscreen
357     m_windowData->toggleFullscreen(false);
358     m_currentViewMode = m_initialViewMode;
359     m_isWebkitFullscreen = false;
360 }
361
362 void WrtClient::launchStep()
363 {
364     ADD_PROFILING_POINT("launchStep", "start");
365     LogDebug("Launching widget ...");
366
367     ADD_PROFILING_POINT("getRunnableWidgetObject", "start");
368     m_widget = WRT::CoreModuleSingleton::Instance()
369             .getRunnableWidgetObject(m_tizenId);
370     ADD_PROFILING_POINT("getRunnableWidgetObject", "stop");
371
372     if (!m_widget) {
373         LogError("RunnableWidgetObject is NULL, stop launchStep");
374         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
375             NextStepEvent());
376         return;
377     }
378
379     if (m_widgetState == WidgetState_Running) {
380         LogWarning("Widget already running, stop launchStep");
381         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
382             NextStepEvent());
383         return;
384     }
385
386     if (m_widgetState == WidgetState_Authorizing) {
387         LogWarning("Widget already authorizing, stop launchStep");
388         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
389             NextStepEvent());
390         return;
391     }
392
393     m_dao.reset(new WrtDB::WidgetDAOReadOnly(DPL::FromASCIIString(m_tizenId)));
394     WrtDB::WidgetSettings widgetSettings;
395     m_dao->getWidgetSettings(widgetSettings);
396     m_settingList.reset(new WidgetSettingList(widgetSettings));
397     m_submodeSupport->initialize(DPL::FromASCIIString(m_tizenId));
398
399     DPL::Optional<DPL::String> defloc = m_dao->getDefaultlocale();
400     if (!defloc.IsNull()) {
401         LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
402             *defloc);
403     }
404
405     setInitialViewMode();
406
407     /* remove language change callback */
408     /*
409     LocalizationSetting::SetLanguageChangedCallback(
410             languageChangedCallback, this);
411     */
412
413     ADD_PROFILING_POINT("CreateWindow", "start");
414     if (s_preparedWindowData == NULL) {
415         m_windowData.reset(new WindowData(static_cast<unsigned long>(getpid()), true));
416     } else {
417         m_windowData.reset(s_preparedWindowData);
418         s_preparedWindowData = NULL;
419     }
420     ADD_PROFILING_POINT("CreateWindow", "stop");
421     if (!m_windowData->initScreenReaderSupport(
422             m_settingList->getAccessibility() == Accessibility_Enable))
423     {
424         LogWarning("Fail to set screen reader support set");
425     }
426
427     // rotate window to initial value
428     setWindowInitialOrientation();
429     setCtxpopupItem();
430
431     WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
432
433     ADD_PROFILING_POINT("Create splash screen", "start");
434     DPL::OptionalString splashImgSrc = m_dao->getSplashImgSrc();
435     if (!splashImgSrc.IsNull())
436     {
437         m_splashScreen.reset(
438             new SplashScreenSupport(
439                 m_windowData->getEvasObject(Layer::WINDOW),
440                 (DPL::ToUTF8String(*splashImgSrc)).c_str(),
441                 m_currentViewMode != VIEWMODE_TYPE_FULLSCREEN,
442                 m_settingList->getRotationValue() == Screen_Landscape));
443         m_splashScreen->startSplashScreen();
444     }
445     ADD_PROFILING_POINT("Create splash screen", "stop");
446
447     DPL::OptionalString startUrl = W3CFileLocalization::getStartFile(m_dao);
448     if (!m_widget->PrepareView(
449             DPL::ToUTF8String(*startUrl),
450             m_windowData->getEvasObject(Layer::WINDOW),
451             s_preparedEwkContext))
452     {
453         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
454             NextStepEvent());
455         return;
456     }
457     // send rotate information to ewk
458     setEwkInitialOrientation();
459
460     //you can't show window with splash screen before PrepareView
461     //ewk_view_add_with_context() in viewLogic breaks window
462     m_windowData->init();
463     m_windowData->postInit();
464
465 #if X11
466     // sub-mode support
467     if (m_submodeSupport->isInlineMode()) {
468         if (m_submodeSupport->transientWindow(
469                 elm_win_xwindow_get(
470                     m_windowData->getEvasObject(Layer::WINDOW))))
471         {
472             LogDebug("Success to set submode");
473         } else {
474             LogWarning("Fail to set submode");
475         }
476     }
477 #endif
478     m_windowData->smartCallbackAdd(Layer::FOCUS,
479                                    "focused",
480                                    focusedCallback,
481                                    this);
482     m_windowData->smartCallbackAdd(Layer::FOCUS,
483                                    "unfocused",
484                                    unfocusedCallback,
485                                    this);
486
487     WrtDB::WidgetLocalizedInfo localizedInfo =
488         W3CFileLocalization::getLocalizedInfo(m_dao);
489     std::string name = "";
490     if (!(localizedInfo.name.IsNull())) {
491         name = DPL::ToUTF8String(*(localizedInfo.name));
492     }
493     elm_win_title_set(m_windowData->getEvasObject(Layer::WINDOW),
494                       name.c_str());
495
496     // window show
497     evas_object_show(m_windowData->getEvasObject(Layer::WINDOW));
498
499     initializeWindowModes();
500
501     m_widgetState = WidgetState_Authorizing;
502     if (!m_widget->CheckBeforeLaunch()) {
503         LogError("CheckBeforeLaunch failed, stop launchStep");
504         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
505             NextStepEvent());
506         return;
507     }
508     LogDebug("Widget launch accepted. Entering running state");
509     m_widgetState = WidgetState_Running;
510
511     cbs->progressStarted = DPL::MakeDelegate(this, &WrtClient::progressStartedCallback);
512     cbs->progress = DPL::MakeDelegate(this, &WrtClient::loadProgressCallback);
513     cbs->progressFinish = DPL::MakeDelegate(this, &WrtClient::progressFinishCallback);
514     cbs->loadFinish = DPL::MakeDelegate(this, &WrtClient::loadFinishCallback);
515     cbs->reset = DPL::MakeDelegate(this, &WrtClient::resetCallback);
516     cbs->bufferSet = DPL::MakeDelegate(this, &WrtClient::setLayout);
517     cbs->bufferUnset = DPL::MakeDelegate(this, &WrtClient::unsetLayout);
518     cbs->webkitExit = DPL::MakeDelegate(this, &WrtClient::webkitExitCallback);
519     cbs->webCrash = DPL::MakeDelegate(this, &WrtClient::webCrashCallback);
520     cbs->enterFullscreen = DPL::MakeDelegate(this, &WrtClient::enterFullscreenCallback);
521     cbs->exitFullscreen = DPL::MakeDelegate(this, &WrtClient::exitFullscreenCallback);
522     cbs->setOrientation = DPL::MakeDelegate(this, &WrtClient::setWindowOrientation);
523     cbs->hwkey = DPL::MakeDelegate(this, &WrtClient::hwkeyCallback);
524
525     m_widget->SetUserDelegates(cbs);
526     m_widget->Show();
527
528     ADD_PROFILING_POINT("launchStep", "stop");
529 }
530
531 void WrtClient::initializeWindowModes()
532 {
533     Assert(m_windowData);
534     bool backbutton =
535         (m_settingList->getBackButtonPresence() == BackButton_Enable ||
536         m_currentViewMode == VIEWMODE_TYPE_WINDOWED);
537     m_windowData->setViewMode(m_currentViewMode == VIEWMODE_TYPE_FULLSCREEN,
538                               backbutton);
539 }
540
541 Eina_Bool WrtClient::naviframeBackButtonCallback(void* data,
542                                                  Elm_Object_Item* /*it*/)
543 {
544     LogDebug("BackButtonCallback");
545     Assert(data);
546
547     WrtClient* This = static_cast<WrtClient*>(data);
548     This->m_widget->Backward();
549     return EINA_FALSE;
550 }
551
552 int WrtClient::appcoreLowMemoryCallback(void* /*data*/)
553 {
554     LogDebug("appcoreLowMemoryCallback");
555     //WrtClient* This = static_cast<WrtClient*>(data);
556
557     // TODO call RunnableWidgetObject API regarding low memory
558     // The API should be implemented
559
560     // temporary solution because we have no way to get ewk_context from runnable object.
561     if (s_preparedEwkContext)
562     {
563         ewk_context_cache_clear(s_preparedEwkContext);
564         ewk_context_notify_low_memory(s_preparedEwkContext);
565     }
566
567     return 0;
568 }
569
570 void WrtClient::setInitialViewMode(void)
571 {
572     Assert(m_dao);
573     WrtDB::WindowModeList windowModes = m_dao->getWindowModes();
574     FOREACH(it, windowModes) {
575         std::string viewMode = DPL::ToUTF8String(*it);
576         switch(viewMode[0]) {
577             case 'f':
578                 if (viewMode == VIEWMODE_TYPE_FULLSCREEN) {
579                     m_initialViewMode = viewMode;
580                     m_currentViewMode = m_initialViewMode;
581                     break;
582                 }
583                 break;
584             case 'm':
585                 if (viewMode == VIEWMODE_TYPE_MAXIMIZED) {
586                     m_initialViewMode = viewMode;
587                     m_currentViewMode = m_initialViewMode;
588                     break;
589                 }
590                 break;
591             case 'w':
592                 if (viewMode == VIEWMODE_TYPE_WINDOWED) {
593                     m_initialViewMode = viewMode;
594                     m_currentViewMode = m_initialViewMode;
595                     break;
596                 }
597                 break;
598             default:
599                 break;
600         }
601     }
602 }
603
604 void WrtClient::setWindowInitialOrientation(void)
605 {
606     Assert(m_windowData);
607     Assert(m_dao);
608
609     WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue();
610     if (rotationValue == Screen_Portrait) {
611         setWindowOrientation(OrientationAngle::Window::Portrait::PRIMARY);
612     } else if (rotationValue == Screen_Landscape) {
613         setWindowOrientation(OrientationAngle::Window::Landscape::PRIMARY);
614     } else if (rotationValue == Screen_AutoRotation) {
615         if (!AutoRotationSupport::setAutoRotation(
616                 m_windowData->getEvasObject(Layer::WINDOW),
617                 autoRotationCallback,
618                 this))
619         {
620             LogError("Fail to set auto rotation");
621         }
622     } else {
623         setWindowOrientation(OrientationAngle::Window::Portrait::PRIMARY);
624     }
625 }
626
627 void WrtClient::setWindowOrientation(int angle)
628 {
629     Assert(m_windowData);
630     m_windowData->setOrientation(angle);
631 }
632
633 void WrtClient::unsetWindowOrientation(void)
634 {
635     Assert(m_windowData);
636     Assert(m_dao);
637
638     WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue();
639     if (rotationValue == Screen_AutoRotation) {
640         AutoRotationSupport::unsetAutoRotation(
641             m_windowData->getEvasObject(Layer::WINDOW),
642             autoRotationCallback);
643     }
644 }
645
646 void WrtClient::setEwkInitialOrientation(void)
647 {
648     Assert(m_widget);
649     Assert(m_dao);
650
651     WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue();
652     if (rotationValue == Screen_Portrait) {
653         ewk_view_orientation_send(
654             m_widget->GetCurrentWebview(),
655              OrientationAngle::W3C::Portrait::PRIMARY);
656     } else if (rotationValue == Screen_Landscape) {
657         ewk_view_orientation_send(
658             m_widget->GetCurrentWebview(),
659             OrientationAngle::W3C::Landscape::PRIMARY);
660     } else if (rotationValue == Screen_AutoRotation) {
661          ewk_view_orientation_send(
662             m_widget->GetCurrentWebview(),
663             OrientationAngle::W3C::Portrait::PRIMARY);
664     } else {
665         ewk_view_orientation_send(
666             m_widget->GetCurrentWebview(),
667             OrientationAngle::W3C::Portrait::PRIMARY);
668     }
669 }
670
671 void WrtClient::ExitCallback(void* data,
672                                    Evas_Object * /*obj*/,
673                                    void * /*event_info*/)
674 {
675     LogInfo("ExitCallback");
676     Assert(data);
677
678     WrtClient* This = static_cast<WrtClient*>(data);
679
680     This->OnTerminate();
681 }
682
683 void WrtClient::setCtxpopupItem(void)
684 {
685     WindowData::CtxpopupItemDataList data;
686
687     // 1. share
688     WindowData::CtxpopupCallbackType shareCallback =
689         DPL::MakeDelegate(this, &WrtClient::ctxpopupShare);
690     WindowData::CtxpopupItemData shareData("Share",
691                                            std::string(),
692                                            shareCallback);
693
694     // 2. reload
695     WindowData::CtxpopupCallbackType reloadCallback =
696         DPL::MakeDelegate(this, &WrtClient::ctxpopupReload);
697     WindowData::CtxpopupItemData reloadData("Reload",
698                                             std::string(),
699                                             reloadCallback);
700
701     // 3. Open in browser
702     WindowData::CtxpopupCallbackType launchBrowserCallback =
703         DPL::MakeDelegate(this, &WrtClient::ctxpopupLaunchBrowser);
704     WindowData::CtxpopupItemData launchBrowserData("Open in browser",
705                                                    std::string(),
706                                                    launchBrowserCallback);
707     data.push_back(shareData);
708     data.push_back(reloadData);
709     data.push_back(launchBrowserData);
710     m_windowData->setCtxpopupItemData(data);
711 }
712
713 void WrtClient::ctxpopupShare(void)
714 {
715     LogDebug("share");
716 #ifdef X11
717     const char* url = ewk_view_url_get(m_widget->GetCurrentWebview());
718     if (!url) {
719         LogError("url is empty");
720         return;
721     }
722     if (ClientModule::ServiceSupport::launchShareService(
723             elm_win_xwindow_get(m_windowData->getEvasObject(Layer::WINDOW)),
724             url))
725     {
726         LogDebug("success");
727     } else {
728         LogDebug("fail");
729     }
730     evas_object_smart_callback_add(m_windowData->m_win,
731             "delete,request",
732             &WrtClient::ExitCallback,
733             this);
734 #endif
735 }
736
737 void WrtClient::ctxpopupReload(void)
738 {
739     LogDebug("reload");
740     ewk_view_reload(m_widget->GetCurrentWebview());
741 }
742
743 void WrtClient::ctxpopupLaunchBrowser(void)
744 {
745     LogDebug("launchBrowser");
746 #ifdef X11
747     const char* url = ewk_view_url_get(m_widget->GetCurrentWebview());
748     if (!url) {
749         LogError("url is empty");
750         return;
751     }
752     if (ClientModule::ServiceSupport::launchViewService(
753             elm_win_xwindow_get(m_windowData->getEvasObject(Layer::WINDOW)),
754             url))
755     {
756         LogDebug("success");
757     } else {
758         LogDebug("fail");
759     }
760 #endif
761 }
762
763 void WrtClient::hwkeyCallback(const std::string& key)
764 {
765     if (m_settingList->getBackButtonPresence() == BackButton_Enable
766         || m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
767     {
768         // windowed UX - hosted application
769         if (key == KeyName::BACK) {
770             if (m_isWebkitFullscreen) {
771                 // FIXME!!! This method has not yet landed in the tizen 3.0
772                 //          webkit-efl source tree
773                 //ewk_view_fullscreen_exit(m_widget->GetCurrentWebview());
774             } else {
775                 m_widget->Backward();
776             }
777         } else if (key == KeyName::MENU) {
778             // UX isn't confirmed
779             // m_windowData->showCtxpopup();
780         }
781     }
782 }
783
784 void WrtClient::setLayout(Evas_Object* webview)
785 {
786     LogDebug("add new webkit buffer to window");
787     Assert(webview);
788     m_windowData->setWebview(webview);
789     evas_object_show(webview);
790 }
791
792 void WrtClient::unsetLayout(Evas_Object* webview)
793 {
794     LogDebug("remove current webkit buffer from window");
795     Assert(webview);
796     evas_object_hide(webview);
797     m_windowData->unsetWebview();
798 }
799
800 void WrtClient::shutdownStep()
801 {
802     LogDebug("Closing Wrt connection ...");
803
804     if (m_widget && m_widgetState) {
805         m_widgetState = WidgetState_Stopped;
806         m_widget->Hide();
807         // AutoRotation, focusCallback use m_widget pointer internally.
808         // It must be unset before m_widget is released.
809         m_submodeSupport->deinitialize();
810         unsetWindowOrientation();
811         m_windowData->smartCallbackDel(Layer::FOCUS,
812                                        "focused",
813                                        focusedCallback);
814         m_windowData->smartCallbackDel(Layer::FOCUS,
815                                        "unfocused",
816                                        unfocusedCallback);
817         m_widget.reset();
818         ewk_context_delete(s_preparedEwkContext);
819         WRT::CoreModuleSingleton::Instance().Terminate();
820     }
821     if (m_initialized) {
822         m_initialized = false;
823     }
824     m_windowData.reset();
825     Quit();
826 }
827
828 void WrtClient::autoRotationCallback(void* data, Evas_Object* obj, void* /*event*/)
829 {
830     LogDebug("entered");
831
832     Assert(data);
833     Assert(obj);
834
835     WrtClient* This = static_cast<WrtClient*>(data);
836     This->autoRotationSetOrientation(obj);
837 }
838
839 void WrtClient::focusedCallback(void* data,
840                                 Evas_Object* /*obj*/,
841                                 void* /*eventInfo*/)
842 {
843     LogDebug("entered");
844     Assert(data);
845     WrtClient* This = static_cast<WrtClient*>(data);
846     elm_object_focus_set(This->m_widget->GetCurrentWebview(), EINA_TRUE);
847 }
848
849 void WrtClient::unfocusedCallback(void* data,
850                                 Evas_Object* /*obj*/,
851                                 void* /*eventInfo*/)
852 {
853     LogDebug("entered");
854     Assert(data);
855     WrtClient* This = static_cast<WrtClient*>(data);
856     elm_object_focus_set(This->m_widget->GetCurrentWebview(), EINA_FALSE);
857 }
858
859 void WrtClient::autoRotationSetOrientation(Evas_Object* obj)
860 {
861     LogDebug("entered");
862     Assert(obj);
863
864     AutoRotationSupport::setOrientation(obj, m_widget->GetCurrentWebview(),
865                                 (m_splashScreen) ? m_splashScreen.get(): NULL);
866 }
867
868 int WrtClient::languageChangedCallback(void *data)
869 {
870     LogDebug("Language Changed");
871     if (!data) {
872         return 0;
873     }
874     WrtClient* wrtClient = static_cast<WrtClient*>(data);
875     if (!(wrtClient->m_dao)) {
876         return 0;
877     }
878
879     // reset function fetches system locales and recreates language tags
880     LanguageTagsProviderSingleton::Instance().resetLanguageTags();
881     // widget default locales are added to language tags below
882     DPL::OptionalString defloc = wrtClient->m_dao->getDefaultlocale();
883     if (!defloc.IsNull()) {
884         LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
885             *defloc);
886     }
887
888     if (wrtClient->m_launched &&
889         wrtClient->m_widgetState != WidgetState_Stopped)
890     {
891         wrtClient->m_widget->ReloadStartPage();
892     }
893     return 0;
894 }
895
896 void WrtClient::Quit()
897 {
898     ewk_shutdown();
899     DPL::Application::Quit();
900 }
901
902 static Eina_Bool proces_pool_fd_handler(void* /*data*/, Ecore_Fd_Handler *handler)
903 {
904     int fd = ecore_main_fd_handler_fd_get(handler);
905
906     if (fd == -1)
907     {
908         LogDebug("ECORE_FD_GET");
909         exit(-1);
910     }
911
912     if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR))
913     {
914         LogDebug("ECORE_FD_ERROR");
915         close(fd);
916         exit(-1);
917     }
918
919     if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ))
920     {
921         LogDebug("ECORE_FD_READ");
922         {
923             app_pkt_t* pkt = (app_pkt_t*) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
924             memset(pkt, 0, AUL_SOCK_MAXBUFF);
925
926             int recv_ret = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0);
927             close(fd);
928
929             if (recv_ret == -1)
930             {
931                 LogDebug("recv error!");
932                 free(pkt);
933                 exit(-1);
934             }
935
936             LogDebug("recv_ret : " << recv_ret << ", pkt->len : " << pkt->len);
937             ecore_main_fd_handler_del(handler);
938             process_pool_launchpad_main_loop(pkt, app_argv[0], &app_argc, &app_argv);
939             free(pkt);
940         }
941         ecore_main_loop_quit();
942     }
943
944     return ECORE_CALLBACK_CANCEL;
945 }
946
947 static void vconf_changed_handler(keynode_t* /*key*/, void* /*data*/)
948 {
949     LogDebug("VCONFKEY_LANGSET vconf-key was changed!");
950
951     // When system language is changed, the candidate process will be created again.
952     exit(-1);
953 }
954
955 void set_env()
956 {
957 #ifndef TIZEN_PUBLIC
958     setenv("COREGL_FASTPATH", "1", 1);
959 #endif
960     setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
961     setenv("CAIRO_GL_LAZY_FLUSHING", "yes", 1);
962     setenv("ELM_IMAGE_CACHE", "0", 1);
963 }
964
965 int main(int argc,
966          char *argv[])
967 {
968     // process pool - store arg's value
969     app_argc = argc;
970     app_argv = argv;
971
972 #ifndef X11
973     // Mesa does a bad job detecting the correct EGL
974     // platform to use, and ends up assuming that the
975     // wrt-client is using X
976     setenv("EGL_PLATFORM", "wayland", 1);
977 #endif
978
979     UNHANDLED_EXCEPTION_HANDLER_BEGIN
980     {
981         ADD_PROFILING_POINT("main-entered", "point");
982
983         // Set log tagging
984         DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
985
986         // Set environment variables
987         set_env();
988
989         if (argc > 1 && argv[1] != NULL && !strcmp(argv[1], "-d"))
990         {
991             LogDebug("Entered dummy process mode");
992             sprintf(argv[0], "%s                                              ",
993                     DUMMY_PROCESS_PATH);
994
995             // Set 'root' home directory
996             setenv(HOME, ROOT_HOME_PATH, 1);
997
998             LogDebug("Prepare ewk_context");
999             appcore_set_i18n("wrt-client", NULL);
1000             ewk_set_arguments(argc, argv);
1001             setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
1002             s_preparedEwkContext = ewk_context_new_with_injected_bundle_path(BUNDLE_PATH);
1003
1004             if (s_preparedEwkContext == NULL)
1005             {
1006                 LogDebug("Creating webkit context was failed!");
1007                 exit(-1);
1008             }
1009
1010             int client_fd = __connect_process_pool_server();
1011
1012             if (client_fd == -1)
1013             {
1014                 LogDebug("Connecting process_pool_server was failed!");
1015                 exit(-1);
1016             }
1017
1018             // register language changed callback
1019             vconf_notify_key_changed(VCONFKEY_LANGSET, vconf_changed_handler, NULL);
1020
1021             LogDebug("Prepare window_data");
1022             // Temporarily change HOME path to app
1023             // This change is needed for getting elementary profile
1024             // /opt/home/app/.elementary/config/mobile/base.cfg
1025             const char* backupEnv = getenv(HOME);
1026             if (!backupEnv) {
1027                 // If getenv return "NULL", set empty string
1028                 backupEnv = "";
1029             }
1030             setenv(HOME, APP_HOME_PATH, 1);
1031             LogDebug("elm_init()");
1032             elm_init(argc, argv);
1033             setenv(HOME, backupEnv, 1);
1034
1035             LogDebug("WindowData()");
1036             s_preparedWindowData = new WindowData(static_cast<unsigned long>(getpid()));
1037
1038             Ecore_Fd_Handler* fd_handler = ecore_main_fd_handler_add(client_fd,
1039                                            (Ecore_Fd_Handler_Flags)(ECORE_FD_READ|ECORE_FD_ERROR),
1040                                            proces_pool_fd_handler, NULL, NULL, NULL);
1041
1042             if (fd_handler == NULL)
1043             {
1044                 LogDebug("fd_handler is NULL");
1045                 exit(-1);
1046             }
1047
1048             setpriority(PRIO_PROCESS, 0, 0);
1049
1050             LogDebug("ecore_main_loop_begin()");
1051             ecore_main_loop_begin();
1052             LogDebug("ecore_main_loop_begin()_end");
1053
1054             // deregister language changed callback
1055             vconf_ignore_key_changed(VCONFKEY_LANGSET, vconf_changed_handler);
1056
1057             std::string tizenId =
1058                 ClientModule::CommandLineParser::getTizenId(argc, argv);
1059             ewk_context_message_post_to_injected_bundle(
1060                 s_preparedEwkContext,
1061                 MESSAGE_NAME_INITIALIZE,
1062                 tizenId.c_str());
1063
1064         }
1065         else
1066         {
1067             // This code is to fork a web process without exec.
1068             std::string tizenId =
1069                 ClientModule::CommandLineParser::getTizenId(argc, argv);
1070
1071             if (!tizenId.empty()) {
1072                 if (UID_ROOT == getuid()) {
1073                     // Drop root permission
1074                     // Only launch web application by console command case has root permission
1075                     if (!ClientModule::SecuritySupport::setAppPrivilege(tizenId)) {
1076                         LogError("Fail to set app privilege : [" << tizenId << "]");
1077                         exit(-1);
1078                     }
1079                 }
1080
1081                 LogDebug("Launching by fork mode");
1082                 // Language env setup
1083                 appcore_set_i18n("wrt-client", NULL);
1084                 ewk_set_arguments(argc, argv);
1085                 setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
1086                 s_preparedEwkContext = ewk_context_new_with_injected_bundle_path(
1087                         BUNDLE_PATH);
1088
1089                 if (s_preparedEwkContext == NULL)
1090                 {
1091                     LogDebug("Creating webkit context was failed!");
1092                     Wrt::Popup::PopupInvoker().showInfo("Error", "Creating webkit context was failed.", "OK");
1093                     exit(-1);
1094                 }
1095
1096                 // plugin init
1097                 ewk_context_message_post_to_injected_bundle(
1098                     s_preparedEwkContext,
1099                     MESSAGE_NAME_INITIALIZE,
1100                     tizenId.c_str());
1101             }
1102         }
1103
1104         // Output on stdout will be flushed after every newline character,
1105         // even if it is redirected to a pipe. This is useful for running
1106         // from a script and parsing output.
1107         // (Standard behavior of stdlib is to use full buffering when
1108         // redirected to a pipe, which means even after an end of line
1109         // the output may not be flushed).
1110         setlinebuf(stdout);
1111
1112         WrtClient app(app_argc, app_argv);
1113
1114         ADD_PROFILING_POINT("Before appExec", "point");
1115         int ret = app.Exec();
1116         LogDebug("App returned: " << ret);
1117         ret = app.getReturnStatus();
1118         LogDebug("WrtClient returned: " << ret);
1119         return ret;
1120     }
1121     UNHANDLED_EXCEPTION_HANDLER_END
1122 }