Locate ewk_view_page_close in extended main loop
[platform/framework/web/crosswalk-tizen.git] / runtime / browser / ui_runtime.cc
1 /*
2  * Copyright (c) 2015 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
17 #include "runtime/browser/runtime.h"
18
19 #include <Ecore.h>
20
21 #include <memory>
22 #include <string>
23 #include <vector>
24
25 #include "common/application_data.h"
26 #include "common/app_control.h"
27 #include "common/app_db.h"
28 #include "common/command_line.h"
29 #include "common/logger.h"
30 #include "common/profiler.h"
31 #include "runtime/common/constants.h"
32 #include "runtime/browser/native_app_window.h"
33 #include "runtime/browser/notification_window.h"
34 #include "runtime/browser/preload_manager.h"
35 #include "runtime/browser/ui_runtime.h"
36
37 namespace runtime {
38
39 namespace {
40
41 const char kCategoryAlwaysOnTop[] = "http://tizen.org/category/always_on_top";
42
43 static NativeWindow* CreateNativeWindow(NativeWindow::Type windowType) {
44   SCOPE_PROFILE();
45
46   NativeWindow* window;
47
48   switch (windowType) {
49     case NativeWindow::Type::NORMAL: {
50       auto cached = PreloadManager::GetInstance()->GetCachedNativeWindow();
51       window = cached != nullptr ? cached : new NativeAppWindow();
52     }
53     break;
54     case NativeWindow::Type::NOTIFICATION: {
55       PreloadManager::GetInstance()->ReleaseCachedNativeWindow();
56       NotificationWindow* win = new NotificationWindow();
57       window = win;
58     }
59     break;
60   }
61
62   window->Initialize();
63   return window;
64 }
65
66 bool HasAlwaysTopCategory(
67     const std::vector<std::string>& category_info_list) {
68   for (const auto& category : category_info_list) {
69       if (strcmp(category.c_str(), kCategoryAlwaysOnTop) == 0)
70         return true;
71     }
72     return false;
73 }
74
75 bool AlwaysTopRequested(common::AppControl* appcontrol) {
76   return appcontrol->data("always_on_top") == "true";
77 }
78
79 }  // namespace
80
81 UiRuntime::UiRuntime(common::ApplicationData* app_data)
82     : native_window_(nullptr),
83       application_(nullptr),
84       context_(
85         ewk_context_new_with_injected_bundle_path(INJECTED_BUNDLE_PATH)),
86       app_data_(app_data) {
87 }
88
89 UiRuntime::~UiRuntime() {
90   application_.reset();
91   native_window_.reset();
92   if (context_)
93       ewk_context_delete(context_);
94 }
95
96 void UiRuntime::ResetWebApplication(NativeWindow::Type windowType) {
97   STEP_PROFILE_START("Runtime ResetWebApplication");
98
99   LOGGER(DEBUG) << "runtime.cc ResetWebApplication() started";
100
101   application_.reset();
102   native_window_.reset();
103
104   native_window_.reset(CreateNativeWindow(windowType));
105   LOGGER(DEBUG) << "runtime.cc Created native window";
106   application_.reset(new WebApplication(native_window_.get(),
107                                         app_data_,
108                                         context_));
109   LOGGER(DEBUG) << "runtime.cc created web application";
110   application_->set_terminator([](){ ui_app_exit(); });
111
112   LOGGER(DEBUG) << "runtime.cc ResetWebApplication() finished";
113
114   STEP_PROFILE_END("Runtime ResetWebApplication");
115 }
116
117 bool UiRuntime::OnCreate() {
118   STEP_PROFILE_END("ui_app_main -> OnCreate");
119   STEP_PROFILE_END("Start -> OnCreate");
120   STEP_PROFILE_START("OnCreate -> URL Set");
121
122   common::CommandLine* cmd = common::CommandLine::ForCurrentProcess();
123   std::string appid = cmd->GetAppIdFromCommandLine(kRuntimeExecName);
124
125   // Init AppDB for Runtime
126   common::AppDB* appdb = common::AppDB::GetInstance();
127   appdb->Set(kAppDBRuntimeSection, kAppDBRuntimeName, "xwalk-tizen");
128   appdb->Set(kAppDBRuntimeSection, kAppDBRuntimeAppID, appid);
129   if (app_data_->setting_info()->background_support_enabled()) {
130     appdb->Set(kAppDBRuntimeSection, kAppDBRuntimeBackgroundSupport, "true");
131   } else {
132     appdb->Set(kAppDBRuntimeSection, kAppDBRuntimeBackgroundSupport, "false");
133   }
134   appdb->Remove(kAppDBRuntimeSection, kAppDBRuntimeBundle);
135
136   ResetWebApplication(NativeWindow::Type::NORMAL);
137
138   setlocale(LC_ALL, "");
139   bindtextdomain(kTextDomainRuntime, kTextLocalePath);
140
141   return true;
142 }
143
144 void UiRuntime::OnTerminate() {
145 }
146
147 void UiRuntime::Terminate() {
148   LOGGER(DEBUG);
149   ProcessClosingPage(application_.get());
150 }
151
152 void UiRuntime::OnPause() {
153   if (application_->launched()) {
154     application_->Suspend();
155   }
156 }
157
158 void UiRuntime::OnResume() {
159   if (application_->launched()) {
160     application_->Resume();
161   }
162 }
163
164 void UiRuntime::OnAppControl(app_control_h app_control) {
165   SCOPE_PROFILE();
166   std::unique_ptr<common::AppControl>
167       appcontrol(new common::AppControl(app_control));
168   common::AppDB* appdb = common::AppDB::GetInstance();
169   appdb->Set(kAppDBRuntimeSection, kAppDBRuntimeBundle,
170              appcontrol->encoded_bundle());
171
172   bool reset_webapp = false;
173   NativeWindow::Type type;
174   if (AlwaysTopRequested(appcontrol.get()) &&
175       HasAlwaysTopCategory(app_data_->category_info_list()->categories)) {
176     if (native_window_->type() != NativeWindow::Type::NOTIFICATION) {
177       type = NativeWindow::Type::NOTIFICATION;
178       reset_webapp = true;
179     }
180   } else {
181     if (native_window_->type() != NativeWindow::Type::NORMAL) {
182       type = NativeWindow::Type::NORMAL;
183       reset_webapp = true;
184     }
185   }
186
187   if (reset_webapp) {
188     ResetWebApplication(type);
189     // TODO(t.iwanek): there is still problem with rendering content if
190     // window is replaced ewk won't render page.
191     // This looks the same as for workaround removed in: PR #80
192     native_window_->Show();
193   }
194
195   if (application_->launched()) {
196     application_->AppControl(std::move(appcontrol));
197   } else {
198     application_->Launch(std::move(appcontrol));
199   }
200 }
201
202 void UiRuntime::OnLanguageChanged(const std::string& language) {
203   if (application_) {
204     application_->OnLanguageChanged();
205     elm_language_set(language.c_str());
206   }
207 }
208
209 void UiRuntime::OnLowMemory() {
210   if (application_) {
211     application_->OnLowMemory();
212   }
213 }
214
215 int UiRuntime::Exec(int argc, char* argv[]) {
216   ui_app_lifecycle_callback_s ops = {NULL, NULL, NULL, NULL, NULL};
217
218   // onCreate
219   ops.create = [](void* data) -> bool {
220     UiRuntime* ui_runtime = reinterpret_cast<UiRuntime*>(data);
221     if (!ui_runtime) {
222       LOGGER(ERROR) << "UiRuntime has not been created.";
223       return false;
224     }
225     return ui_runtime->OnCreate();
226   };
227
228   // onTerminate
229   ops.terminate = [](void* data) -> void {
230     UiRuntime* ui_runtime = reinterpret_cast<UiRuntime*>(data);
231     if (!ui_runtime) {
232       LOGGER(ERROR) << "UiRuntime has not been created.";
233       return;
234     }
235     ui_runtime->OnTerminate();
236   };
237
238   // onPause
239   ops.pause = [](void* data) -> void {
240     UiRuntime* ui_runtime = reinterpret_cast<UiRuntime*>(data);
241     if (!ui_runtime) {
242       LOGGER(ERROR) << "UiRuntime has not been created.";
243       return;
244     }
245     ui_runtime->OnPause();
246   };
247
248   // onResume
249   ops.resume = [](void* data) -> void {
250     UiRuntime* ui_runtime = reinterpret_cast<UiRuntime*>(data);
251     if (!ui_runtime) {
252       LOGGER(ERROR) << "UiRuntime has not been created.";
253       return;
254     }
255     ui_runtime->OnResume();
256   };
257
258   // onAppControl
259   ops.app_control = [](app_control_h app_control, void* data) -> void {
260     UiRuntime* ui_runtime = reinterpret_cast<UiRuntime*>(data);
261     if (!ui_runtime) {
262       LOGGER(ERROR) << "UiRuntime has not been created.";
263       return;
264     }
265     ui_runtime->OnAppControl(app_control);
266   };
267
268   // language changed callback
269   auto language_changed = [](app_event_info_h event_info, void* user_data) {
270     char* str;
271     if (app_event_get_language(event_info, &str) == 0 && str != NULL) {
272       std::string language = std::string(str);
273       std::free(str);
274       UiRuntime* ui_runtime = reinterpret_cast<UiRuntime*>(user_data);
275       ui_runtime->OnLanguageChanged(language);
276     }
277   };
278   auto low_memory = [](app_event_info_h /*event_info*/, void* user_data) {
279     UiRuntime* ui_runtime = reinterpret_cast<UiRuntime*>(user_data);
280     ui_runtime->OnLowMemory();
281   };
282   app_event_handler_h ev_handle;
283   ui_app_add_event_handler(&ev_handle,
284                            APP_EVENT_LANGUAGE_CHANGED,
285                            language_changed,
286                            this);
287   ui_app_add_event_handler(&ev_handle,
288                            APP_EVENT_LOW_MEMORY,
289                            low_memory,
290                            this);
291   STEP_PROFILE_START("ui_app_main -> OnCreate");
292
293   return ui_app_main(argc, argv, &ops, this);
294 }
295
296 }  // namespace runtime