[WRTjs] Refactor popup
[platform/framework/web/chromium-efl.git] / wrt / src / browser / wrt_native_window.cc
1 // Copyright 2015 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "wrt/src/browser/wrt_native_window.h"
6
7 #include <Ecore_Wl2.h>
8 #include <Elementary.h>
9
10 #include <efl_extension.h>
11 #include <map>
12
13 #include "base/base_switches.h"
14 #include "base/command_line.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
17 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/browser/web_contents/web_contents_view_aura.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "electron/shell/browser/window_list.h"
23 #include "electron/shell/common/gin_helper/dictionary.h"
24 #include "electron/shell/common/options_switches.h"
25 #include "tizen_src/chromium_impl/efl/window_factory.h"
26 #include "tizen_src/chromium_impl/tizen/system_info.h"
27 #include "ui/compositor/compositor_observer_efl.h"
28 #include "ui/display/screen.h"
29 #include "ui/gfx/geometry/rect.h"
30 #include "ui/gfx/geometry/size.h"
31 #include "ui/gfx/image/image.h"
32 #include "wrt/src/browser/splash_screen.h"
33 #include "wrt/src/browser/wrt_frame_view.h"
34 #include "wrt/src/browser/wrt_native_widget.h"
35 #include "wrt/src/browser/wrt_native_window_off_screen.h"
36 #include "wrt/src/browser/wrt_native_window_on_screen.h"
37 #include "wrt/src/browser/wrt_web_contents.h"
38 #include "wrt/src/browser/wrt_window_tree_host.h"
39 #include "wrt/src/common/application_data.h"
40 #include "wrt/src/common/wrt_profile_delegate.h"
41
42 #if defined(TIZEN_ATK_SUPPORT)
43 #include "tizen_src/ewk/efl_integration/eweb_accessibility.h"
44 #include "tizen_src/ewk/efl_integration/eweb_accessibility_util.h"
45 #endif
46
47 #if BUILDFLAG(IS_TIZEN_TV)
48 #include "wrt/src/browser/tv/wrt_native_window_tv.h"
49
50 using WRTNativeWindowType = wrt::WRTNativeWindowTV;
51 #else
52 using WRTNativeWindowType = wrt::WRTNativeWindow;
53 #endif
54
55 namespace wrt {
56
57 namespace {
58
59 const char* kBackKeyEventScript =
60     "(function(){"
61     "var __event = document.createEvent(\"CustomEvent\");\n"
62     "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
63     "__event.keyName = \"back\";\n"
64     "document.dispatchEvent(__event);\n"
65     "\n"
66     "for (var i=0; i < window.frames.length; i++)\n"
67     "{ window.frames[i].document.dispatchEvent(__event); }"
68     "})()";
69 const char* kMenuKeyEventScript =
70     "(function(){"
71     "var __event = document.createEvent(\"CustomEvent\");\n"
72     "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
73     "__event.keyName = \"menu\";\n"
74     "document.dispatchEvent(__event);\n"
75     "\n"
76     "for (var i=0; i < window.frames.length; i++)\n"
77     "{ window.frames[i].document.dispatchEvent(__event); }"
78     "})()";
79
80 const int kPortraitNaturalAngle[] = {
81     0,    // PORTRAIT_PRIMARY
82     180,  // PORTRAIT_SECONDARY
83     270,  // LANDSCAPE_PRIMARY
84     90,   // LANDSCAPE_SECONDARY
85     0,    // NATURAL
86     -1    // ANY
87 };
88
89 const int kLandscapeNaturalAngle[] = {
90     90,  // PORTRAIT_PRIMARY
91     270,   // PORTRAIT_SECONDARY
92     0,    // LANDSCAPE_PRIMARY
93     180,  // LANDSCAPE_SECONDARY
94     0,    // NATURAL
95     -1,   // ANY
96 };
97
98 #if !BUILDFLAG(IS_TIZEN_TV)
99 const char* kFileScheme = "file";
100 const std::string kViewmodeTypeWindowed = "windowed";
101 #endif
102
103 std::unique_ptr<WRTNativeWindowDelegate> native_window_delegate;
104 bool use_onscreen_rendering = true;
105 Ecore_Evas* platform_canvas = nullptr;
106
107 Ecore_Event_Handler* visibility_handler_ = nullptr;
108 int ime_width = 0;
109 int ime_height = 0;
110 int rotation_degree = 0;
111
112 void AddVisibilityEventListener() {
113   LOG(INFO) << "Add event listener for visibility change";
114 #if TIZEN_VERSION_AT_LEAST(7, 0, 0)
115   // From Tizen 7.0, EFL supports 'ecore_wl2_window_visibility_callback_set'
116   // to notify visibility change status early than ecore event.
117   // This callback is invoked at '_tizen_visibility_cb_notify' when wayland IPC
118   // is handled.
119   auto visibility_callback = [](void* user_data, Ecore_Wl2_Window* win,
120                                 Eina_Bool visibility) {
121     /* It's fundamental to send visibility events to the latest created
122        page, to retain compatibility and for passing "Page Visibility Test"
123       in tct-behavior tests */
124     auto* native_window = WRTNativeWindow::GetActiveNativeWindow();
125     if (native_window &&
126         native_window->IsSameWindowId(ecore_wl2_window_id_get(win))) {
127       native_window->SetPageVisibility(visibility == EINA_TRUE);
128     } else {
129       LOG(ERROR) << "Window " << ecore_wl2_window_id_get(win)
130                  << " visibility is changed, but it's not app window("
131                  << WRTNativeWindow::GetTopWindow() << "), so skip";
132     }
133   };
134
135   Ecore_Wl2_Window* wl_window = ecore_evas_wayland2_window_get(platform_canvas);
136   ecore_wl2_window_visibility_callback_set(wl_window, visibility_callback,
137                                            nullptr);
138 #else
139   auto visibility_callback = [](void* user_data,
140                                 int /*type*/,
141                                 void* event) -> Eina_Bool {
142     if (!event || electron::WindowList::IsEmpty())
143       return ECORE_CALLBACK_PASS_ON;
144
145     auto* ev = static_cast<Ecore_Wl2_Event_Window_Visibility_Change*>(event);
146     /* It's fundamental to send visibility events to the latest created
147        page, to retain compatibility and for passing "Page Visibility Test"
148       in tct-behavior tests */
149     auto* native_window = WRTNativeWindow::GetActiveNativeWindow();
150     if (native_window && native_window->IsSameWindowId(ev->win)) {
151       native_window->SetPageVisibility(!ev->fully_obscured);
152     } else {
153       LOG(ERROR) << "Window " << ev->win
154                  << " visibility is changed, but it's not app window("
155                  << WRTNativeWindow::GetTopWindow() << "), so skip";
156     }
157
158     return ECORE_CALLBACK_PASS_ON;
159   };
160   // 'prepend' will add to beginning of handler list
161   visibility_handler_ = ecore_event_handler_prepend(
162       ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, visibility_callback, nullptr);
163 #endif
164 }
165
166 int GetRotationDegree(WRTNativeWindow::ScreenOrientation orientation) {
167   auto display_size = display::Screen::GetScreen()->GetPrimaryDisplay().size();
168   WRTNativeWindow::ScreenOrientation natural_orientation;
169   if (display_size.width() > display_size.height())
170     natural_orientation = WRTNativeWindow::ScreenOrientation::LANDSCAPE_PRIMARY;
171   else
172     natural_orientation = WRTNativeWindow::ScreenOrientation::PORTRAIT_PRIMARY;
173
174   if (natural_orientation ==
175       WRTNativeWindow::ScreenOrientation::PORTRAIT_PRIMARY)
176     return kPortraitNaturalAngle[static_cast<int>(orientation)];
177   else
178     return kLandscapeNaturalAngle[static_cast<int>(orientation)];
179 }
180
181 void EnableManualRotation(bool enable) {
182   ecore_evas_wm_rotation_manual_rotation_done_set(
183       platform_canvas, enable ? EINA_TRUE : EINA_FALSE);
184 }
185
186 content::WebContents::Getter GetWebContentsGetter(
187     content::WebContents* web_contents) {
188   // Use the FrameTreeNode ID to get the WebContents
189   int frame_tree_node_id =
190       web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId();
191   if (frame_tree_node_id != content::RenderFrameHost::kNoFrameTreeNodeId) {
192     return base::BindRepeating(content::WebContents::FromFrameTreeNodeId,
193                                frame_tree_node_id);
194   }
195
196   // Use the RenderProcessHostID and RenderFrameHost ID to get the WebContents
197   content::RenderFrameHost* render_frame_host =
198       content::RenderFrameHost::FromID(
199           web_contents->GetPrimaryMainFrame()->GetProcess()->GetID(),
200           web_contents->GetPrimaryMainFrame()->GetRoutingID());
201   if (render_frame_host) {
202     return base::BindRepeating(content::WebContents::FromRenderFrameHost,
203                                render_frame_host);
204   }
205
206   return base::BindRepeating([]() -> content::WebContents* { return nullptr; });
207 }
208
209 }  // namespace
210
211 // static
212 WRTNativeWindow* WRTNativeWindow::GetMainNativeWindow() {
213   return electron::WindowList::IsEmpty()
214              ? nullptr
215              : static_cast<WRTNativeWindow*>(
216                    electron::WindowList::GetWindows().front());
217 }
218
219 // static
220 WRTNativeWindow* WRTNativeWindow::GetActiveNativeWindow() {
221   return electron::WindowList::IsEmpty()
222              ? nullptr
223              : static_cast<WRTNativeWindow*>(
224                    electron::WindowList::GetWindows().back());
225 }
226
227 // static
228 void WRTNativeWindow::EnsurePlatformWindow() {
229   if (!native_window_delegate) {
230     use_onscreen_rendering =
231         !base::CommandLine::ForCurrentProcess()->HasSwitch(
232             switches::kEnableOffscreenRendering);
233     LOG(INFO) << "Use " << (use_onscreen_rendering ? "onscreen" : "offscreen")
234               << " rendering mode";
235     if (use_onscreen_rendering) {
236       native_window_delegate = std::make_unique<WRTNativeWindowOnScreen>();
237     } else {
238       native_window_delegate = std::make_unique<WRTNativeWindowOffScreen>();
239     }
240   }
241   auto* window = native_window_delegate->GetWindowEvasObject();
242   platform_canvas = ecore_evas_ecore_evas_get(evas_object_evas_get(window));
243 }
244
245 // static
246 Evas_Object* WRTNativeWindow::GetHostWindowDelegate(
247     const content::WebContents* web_contents) {
248   if (native_window_delegate)
249     return native_window_delegate->GetWindowEvasObject();
250   else
251     return nullptr;
252 }
253
254 // static
255 Evas_Object* WRTNativeWindow::GetTopWindow() {
256   if (native_window_delegate)
257     return native_window_delegate->GetTopWindow();
258   else
259     return nullptr;
260 }
261
262 // static
263 Evas_Object* WRTNativeWindow::GetConformant() {
264   if (native_window_delegate)
265     return native_window_delegate->GetConformant();
266   else
267     return nullptr;
268 }
269
270 // static
271 Ecore_Evas* WRTNativeWindow::GetPlatformCanvas() {
272   return platform_canvas;
273 }
274
275 // static
276 WRTNativeWindow* WRTNativeWindow::FromWebContents(
277     const content::WebContents* web_contents) {
278   for (const auto& it : electron::WindowList::GetWindows()) {
279     auto window = static_cast<WRTNativeWindow*>(it);
280     if (window->web_contents_ == web_contents)
281       return window;
282   }
283   return nullptr;
284 }
285
286 // static
287 void WRTNativeWindow::HidePlatformWindow() {
288   native_window_delegate->Hide();
289 }
290
291 // static
292 bool WRTNativeWindow::UseOnscreenRendering() {
293   return use_onscreen_rendering;
294 }
295
296 // static
297 WRTNativeWindowDelegate* WRTNativeWindow::GetNativeWindowDelegate() {
298   return native_window_delegate.get();
299 }
300
301 // static
302 void WRTNativeWindow::InitializePlatformEventListeners() {
303   AddVisibilityEventListener();
304
305 #if !BUILDFLAG(IS_TIZEN_TV)
306   AddEditorClientEventListeners();
307 #endif
308
309   auto window = native_window_delegate->GetTopWindow();
310   eext_object_event_callback_add(window, EEXT_CALLBACK_BACK, &OnHWBackKey,
311                                  nullptr);
312   // Custom event 'tizenhwkey' for 'menu' key is sent
313   // only when hwkey is enabled in config.xml as per specs
314   if (ApplicationData::GetInstance().setting_info().hwkey_enabled()) {
315     eext_object_event_callback_add(window, EEXT_CALLBACK_MORE, &OnHWMoreKey,
316                                    nullptr);
317   }
318
319   if (IsWearableProfile())
320     AddRotaryEventListener();
321
322   InitRotation();
323 }
324
325 // static
326 void WRTNativeWindow::CleanupPlatformEventListeners() {
327   auto window = native_window_delegate->GetTopWindow();
328   eext_object_event_callback_del(window, EEXT_CALLBACK_BACK, &OnHWBackKey);
329   if (ApplicationData::GetInstance().setting_info().hwkey_enabled())
330     eext_object_event_callback_del(window, EEXT_CALLBACK_MORE, &OnHWMoreKey);
331
332   if (visibility_handler_)
333     ecore_event_handler_del(visibility_handler_);
334   visibility_handler_ = nullptr;
335 }
336
337 // static
338 void WRTNativeWindow::AddEditorClientEventListeners() {
339   auto window = native_window_delegate->GetTopWindow();
340   auto ime_changed_callback = [](void*, Evas_Object*, void* event_info) {
341     Eina_Rectangle* rect = static_cast<Eina_Rectangle*>(event_info);
342     ime_width = rect->w;
343     ime_height = rect->h;
344   };
345   evas_object_smart_callback_add(window, "inputmethod,changed",
346                                  ime_changed_callback, nullptr);
347
348   auto ime_opened_callback = [](void*, Evas_Object*, void* event_info) {
349     WRTNativeWindow* native_window = GetActiveNativeWindow();
350     if (native_window)
351       native_window->OnSoftKeyboardChangeEvent(true);
352   };
353   evas_object_smart_callback_add(window, "editorclient,ime,opened",
354                                  ime_opened_callback, nullptr);
355
356   auto ime_closed_callback = [](void*, Evas_Object*, void* event_info) {
357     WRTNativeWindow* native_window = GetActiveNativeWindow();
358     if (native_window)
359       native_window->OnSoftKeyboardChangeEvent(false);
360   };
361   evas_object_smart_callback_add(window, "editorclient,ime,closed",
362                                  ime_closed_callback, nullptr);
363 }
364
365 // static
366 void WRTNativeWindow::AddRotaryEventListener() {
367   auto rotary_callback = [](void*, Evas_Object*,
368                             Eext_Rotary_Event_Info* event_info) -> Eina_Bool {
369     for (const auto& it : electron::WindowList::GetWindows()) {
370       auto window = static_cast<WRTNativeWindow*>(it);
371       Eext_Rotary_Event_Info* rotary = event_info;
372       RotaryEventType type;
373       if (rotary->direction == EEXT_ROTARY_DIRECTION_CLOCKWISE)
374         type = RotaryEventType::CLOCKWISE;
375       else
376         type = RotaryEventType::COUNTER_CLOCKWISE;
377       window->OnRotaryEvent(type);
378     }
379     return EINA_TRUE;
380   };
381
382   auto window = native_window_delegate->GetTopWindow();
383   eext_rotary_object_event_callback_add(window, rotary_callback, nullptr);
384   eext_rotary_object_event_activated_set(window, EINA_TRUE);
385 }
386
387 // static
388 void WRTNativeWindow::RotationCallback() {
389   auto rotation = ecore_evas_rotation_get(platform_canvas);
390   if (rotation_degree != rotation) {
391     rotation_degree = rotation;
392     for (const auto& it : electron::WindowList::GetWindows()) {
393       auto window = static_cast<WRTNativeWindow*>(it);
394       window->OnRotation(rotation_degree);
395     }
396   }
397 }
398
399 // static
400 void WRTNativeWindow::InitRotation() {
401   native_window_delegate->InitRotation();
402
403   if (!WRTNativeWindowType::SetRotation()) {
404     auto& setting_info = ApplicationData::GetInstance().setting_info();
405     if (setting_info.screen_orientation() ==
406         wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
407       LOG(INFO) << "ScreenOrientation is AUTO";
408       SetRotationState(true);
409     } else if (setting_info.screen_orientation() ==
410                wgt::parse::SettingInfo::ScreenOrientation::PORTRAIT) {
411       LOG(INFO) << "ScreenOrientation is PORTRAIT_PRIMARY";
412       SetRotationState(
413           false, GetRotationDegree(ScreenOrientation::PORTRAIT_PRIMARY));
414     } else if (setting_info.screen_orientation() ==
415                wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
416       LOG(INFO) << "ScreenOrientation is LANDSCAPE_PRIMARY";
417       SetRotationState(
418           false, GetRotationDegree(ScreenOrientation::LANDSCAPE_PRIMARY));
419     }
420   }
421
422   if (IsMobileProfile())
423     EnableManualRotation(true);
424 }
425
426 // static
427 void WRTNativeWindow::SetRotationState(bool is_auto, int degree) {
428   rotation_degree = native_window_delegate->SetRotationState(is_auto, degree);
429 }
430
431 // static
432 void WRTNativeWindow::OnHWBackKey(void*, Evas_Object*, void*) {
433   if (electron::WindowList::IsEmpty()) {
434     LOG(INFO) << "no window, so not handle back key";
435     return;
436   }
437
438   // TODO: We need to consider to clear selection or exit fullscreen
439   // before send JS custom event.
440   auto* native_window = GetActiveNativeWindow();
441   if (!native_window)
442     return;
443
444   auto* web_contents = native_window->GetWebContents();
445   if (!web_contents)
446     return;
447
448   auto& app_data = ApplicationData::GetInstance();
449   bool hwkey_enabled = app_data.setting_info().hwkey_enabled();
450   if (hwkey_enabled) {
451     content::RenderFrameHost* rfh = web_contents->GetPrimaryMainFrame();
452     if (rfh) {
453       rfh->ExecuteJavaScriptWithUserGestureForTests(
454           base::UTF8ToUTF16(kBackKeyEventScript), base::NullCallback());
455     }
456
457     if (IsWearableProfile() && native_window->IsFullscreen()) {
458       native_window->web_contents_->ExitFullscreen(false);
459       return;
460     }
461   }
462
463 #if !BUILDFLAG(IS_TIZEN_TV)
464   // NOTE: This code is added
465   // 1. to enable back-key on remote URL
466   // 2. for backward compatibility. If the 'backbutton_presence' is true,
467   // WebContents should be navigated back.
468   std::string scheme = web_contents->GetURL().scheme();
469   bool backward_support =
470     app_data.setting_info().backbutton_presence() ||
471     app_data.widget_info().view_modes() == kViewmodeTypeWindowed;
472   if (scheme != kFileScheme || (hwkey_enabled && backward_support)) {
473     if (web_contents->GetController().CanGoBack())
474       web_contents->GetController().GoBack();
475     else
476       native_window->Close();
477   }
478 #endif
479 }
480
481 // static
482 void WRTNativeWindow::OnHWMoreKey(void*, Evas_Object*, void*) {
483   if (electron::WindowList::IsEmpty()) {
484     LOG(INFO) << "no window, so not handle more key";
485     return;
486   }
487
488   if (!GetActiveNativeWindow() ||
489       !GetActiveNativeWindow()->GetRenderFrameHost()) {
490     return;
491   }
492
493   auto* rfh = GetActiveNativeWindow()->GetRenderFrameHost();
494   rfh->ExecuteJavaScriptWithUserGestureForTests(
495       base::UTF8ToUTF16(kMenuKeyEventScript), base::NullCallback());
496 }
497
498 WRTNativeWindow::WRTNativeWindow(const gin_helper::Dictionary& options,
499                                  electron::NativeWindow* parent)
500     : electron::NativeWindow(options, parent),
501       is_main_native_window_(electron::WindowList::GetWindows().size() == 1),
502       web_contents_(nullptr),
503       fullscreenable_(true),
504       visibility_status_(false) {
505   LOG(INFO) << "WRTNativeWindow[" << this << "] create";
506   if (is_main_native_window_) {
507     EnsurePlatformWindow();
508     InitializePlatformEventListeners();
509     // TODO: Find a way to avoid using elementary
510     elm_app_name_set(ApplicationData::GetInstance().app_id().c_str());
511   }
512   options.Get(electron::options::kTitle, &title_);
513
514   auto* host = GetWindowTreeHost();
515   gfx::Rect bounds = host->window()->bounds();
516   views::Widget::InitParams params;
517   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
518   params.bounds = bounds;
519   params.delegate = this;
520   params.type = views::Widget::InitParams::TYPE_WINDOW;
521   params.remove_standard_frame = !has_frame();
522   params.native_widget = new WRTNativeWidget(widget(), host);
523   params.parent = host->window();
524
525   if (transparent())
526     params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
527
528   widget()->Init(std::move(params));
529 }
530
531 WRTNativeWindow::~WRTNativeWindow() {
532   LOG(INFO) << "WRTNativeWindow[" << this << "] start to destroy";
533
534   if (is_main_native_window_) {
535     HidePlatformWindow();
536     CleanupPlatformEventListeners();
537     native_window_delegate->OnNativeWindowDestroyed(this);
538     native_window_delegate.reset();
539   } else {
540     native_window_delegate->OnNativeWindowDestroyed(this);
541   }
542 #if defined(TIZEN_ATK_SUPPORT)
543   EWebAccessibilityUtil::GetInstance()->SetEWebAccessibility(nullptr);
544 #endif
545 }
546
547 void WRTNativeWindow::SetWebContents(content::WebContents* web_contents) {
548   if (web_contents_) {
549     LOG(ERROR) << "Try to initialize multiple times";
550     return;
551   }
552
553   web_contents_ = web_contents;
554   OnRotation(rotation_degree);
555
556   auto window = native_window_delegate->GetTopWindow();
557   static_cast<content::WebContentsImpl*>(web_contents_)->set_ewk_view(window);
558
559 #if defined(TIZEN_ATK_SUPPORT)
560   wrt_accessibility_.reset(
561       new EWebAccessibility(window, web_contents_, nullptr));
562
563   EWebAccessibilityUtil::GetInstance()->SetEWebAccessibility(
564       wrt_accessibility_.get());
565 #endif
566 }
567
568 content::WebContents* WRTNativeWindow::GetWebContents() {
569   CHECK(web_contents_) << "Fail to get web contents";
570   return web_contents_;
571 }
572
573 WRTWindowTreeHost* WRTNativeWindow::GetWindowTreeHost() {
574   return native_window_delegate->GetWindowTreeHost(this);
575 }
576
577 content::RenderFrameHost* WRTNativeWindow::GetRenderFrameHost() {
578   if (GetWebContents())
579     return GetWebContents()->GetPrimaryMainFrame();
580   return nullptr;
581 }
582
583 content::WebContentsViewAura* WRTNativeWindow::GetWebContentsViewAura() {
584   auto* wc = static_cast<content::WebContentsImpl*>(GetWebContents());
585   return static_cast<content::WebContentsViewAura*>(wc->GetView());
586 }
587
588 content::RenderWidgetHostViewAura* WRTNativeWindow::GetRenderWidgetHostView() {
589   if (GetWebContents())
590     return static_cast<content::RenderWidgetHostViewAura*>(
591         GetWebContents()->GetRenderWidgetHostView());
592   return nullptr;
593 }
594
595 void WRTNativeWindow::SetContentView(views::View* view) {
596   auto* wrt_web_contents = WRTWebContents::FromNativeWindow(this);
597   SetWebContents(wrt_web_contents->web_contents());
598
599   native_window_delegate->SetContentView(this, view);
600   set_content_view(view);
601
602   compositor_observer_ = std::make_unique<ui::CompositorObserverEfl>(
603       GetWindowTreeHost()->compositor(),
604       GetWebContentsGetter(GetWebContents()));
605 }
606
607 WRTJavaScriptDialogManager* WRTNativeWindow::GetJavaScriptDialogManager() {
608   auto delegate = web_contents_->GetDelegate();
609   if (!delegate)
610     return nullptr;
611
612   return static_cast<WRTJavaScriptDialogManager*>(
613       delegate->GetJavaScriptDialogManager(nullptr));
614 }
615
616 void WRTNativeWindow::OnRotation(int degree) {
617   content::WebContentsViewAura* aura = GetWebContentsViewAura();
618   if (aura->GetOrientation() == degree)
619     return;
620
621   if (degree % 90 != 0) {
622     LOG(ERROR) << "Received an invalid degree: " << degree;
623     return;
624   }
625
626   aura->SetOrientation(degree);
627
628   auto* dialog_manager = GetJavaScriptDialogManager();
629   if (dialog_manager) {
630     int width, height;
631     ecore_evas_screen_geometry_get(
632         platform_canvas, nullptr, nullptr, &width, &height);
633     if (degree == 90 || degree == 270)
634       std::swap(width, height);
635     dialog_manager->SetPopupSize(width, height);
636   }
637 }
638
639 void WRTNativeWindow::Close() {
640   NotifyWindowCloseButtonClicked();
641 }
642
643 void WRTNativeWindow::CloseImmediately() {
644   if (is_main_native_window_)
645     native_window_delegate->ClearHandlers();
646
647   native_window_delegate->RemoveWidgetClient(this);
648   NotifyWindowClosed();
649 }
650
651 void WRTNativeWindow::Focus(bool focus) {
652   native_window_delegate->Focus(this, focus);
653 }
654
655 bool WRTNativeWindow::IsFocused() {
656   return native_window_delegate->IsFocused(this);
657 }
658
659 void WRTNativeWindow::SetPageVisibility(bool visibility) {
660   LOG(INFO) << "Page visibility changed to " << visibility;
661   auto* rwhv = GetRenderWidgetHostView();
662   auto* aura_efl_helper = rwhv ? rwhv->aura_efl_helper() : nullptr;
663   if (aura_efl_helper)
664     aura_efl_helper->SetPageVisibility(visibility);
665
666   if (visibility) {
667     NotifyWindowShow();
668     Focus(true);
669   } else {
670     NotifyWindowHide();
671   }
672 }
673
674 void WRTNativeWindow::Show() {
675   if (visibility_status_ || IsRunningAsBackground() ||
676       SplashScreen::IsShowing())
677     return;
678
679   if (!GetWebContents()) {
680     LOG(ERROR) << "There's no available window or webview.";
681     return;
682   }
683
684   native_window_delegate->Show(this);
685   visibility_status_ = true;
686 }
687
688 void WRTNativeWindow::ShowInactive() {
689   NOTIMPLEMENTED();
690 }
691
692 void WRTNativeWindow::Hide() {
693   visibility_status_ = false;
694 }
695
696 void WRTNativeWindow::LowerWindow() {
697   ecore_evas_lower(platform_canvas);
698 }
699
700 bool WRTNativeWindow::IsVisible() {
701   return visibility_status_;
702 }
703
704 bool WRTNativeWindow::IsEnabled() {
705   return is_enabled_;
706 }
707
708 void WRTNativeWindow::SetScheduledTasks(bool enable) {
709   auto* wrt_web_contents = WRTWebContents::FromNativeWindow(this);
710   if (!wrt_web_contents) {
711     LOG(WARNING) << "WebContents is not created";
712     return;
713   }
714   auto* render_interface = wrt_web_contents->GetRendererInterface();
715   if (!render_interface) {
716     LOG(WARNING) << "Frame is not created";
717     return;
718   }
719
720   if (enable)
721     render_interface->ResumeScheduledTasks();
722   else
723     render_interface->SuspendScheduledTasks();
724 }
725
726 void WRTNativeWindow::SetEnabled(bool enable) {
727   if (is_enabled_ == enable)
728     return;
729
730   is_enabled_ = enable;
731
732   SetScheduledTasks(enable);
733 }
734
735 void WRTNativeWindow::Maximize() {
736   if (!platform_canvas) {
737     LOG(ERROR) << "There's no available window.";
738     return;
739   }
740   ecore_evas_maximized_set(platform_canvas, EINA_TRUE);
741 }
742
743 void WRTNativeWindow::Unmaximize() {
744   if (!platform_canvas) {
745     LOG(ERROR) << "There's no available window.";
746     return;
747   }
748   ecore_evas_maximized_set(platform_canvas, EINA_FALSE);
749 }
750
751 bool WRTNativeWindow::IsMaximized() {
752   if (!platform_canvas) {
753     LOG(ERROR) << "There's no available window.";
754     return false;
755   }
756   return ecore_evas_maximized_get(platform_canvas);
757 }
758
759 void WRTNativeWindow::Minimize() {
760   NOTIMPLEMENTED();
761 }
762
763 void WRTNativeWindow::Restore() {
764   NOTIMPLEMENTED();
765 }
766
767 bool WRTNativeWindow::IsMinimized() {
768   if (!platform_canvas) {
769     LOG(ERROR) << "There's no available window.";
770     return true;
771   }
772   return !ecore_evas_maximized_get(platform_canvas);
773 }
774
775 void WRTNativeWindow::SetFullScreen(bool fullscreen) {
776   if (!platform_canvas) {
777     LOG(ERROR) << "There's no available window.";
778     return;
779   }
780   ecore_evas_fullscreen_set(platform_canvas, fullscreen);
781 }
782
783 bool WRTNativeWindow::IsFullscreen() const {
784   if (!platform_canvas) {
785     LOG(ERROR) << "There's no available window.";
786     return false;
787   }
788   return ecore_evas_fullscreen_get(platform_canvas);
789 }
790
791 void WRTNativeWindow::SetBounds(const gfx::Rect& bounds, bool animate) {
792   widget()->SetBounds(bounds);
793 }
794
795 gfx::Rect WRTNativeWindow::GetBounds() {
796   return widget()->GetWindowBoundsInScreen();
797 }
798
799 gfx::Rect WRTNativeWindow::GetNormalBounds() {
800   NOTIMPLEMENTED();
801   return gfx::Rect();
802 }
803
804 void WRTNativeWindow::SetResizable(bool resizable) {
805   NOTIMPLEMENTED();
806 }
807
808 bool WRTNativeWindow::MoveAbove(const std::string& sourceId) {
809   NOTIMPLEMENTED();
810   return true;
811 }
812
813 void WRTNativeWindow::MoveTop() {
814   visibility_status_ = false;
815   Show();
816 }
817
818 bool WRTNativeWindow::IsResizable() {
819   NOTIMPLEMENTED();
820   return true;
821 }
822
823 void WRTNativeWindow::SetMovable(bool movable) {
824   NOTIMPLEMENTED();
825 }
826
827 bool WRTNativeWindow::IsMovable() {
828   NOTIMPLEMENTED();
829   return true;
830 }
831
832 void WRTNativeWindow::SetMinimizable(bool minimizable) {
833   NOTIMPLEMENTED();
834 }
835
836 bool WRTNativeWindow::IsMinimizable() {
837   NOTIMPLEMENTED();
838   return true;
839 }
840
841 void WRTNativeWindow::SetMaximizable(bool maximizable) {
842   NOTIMPLEMENTED();
843 }
844
845 bool WRTNativeWindow::IsMaximizable() {
846   NOTIMPLEMENTED();
847   return true;
848 }
849
850 void WRTNativeWindow::SetFullScreenable(bool fullscreenable) {
851   fullscreenable_ = fullscreenable;
852 }
853
854 bool WRTNativeWindow::IsFullScreenable() {
855   return fullscreenable_;
856 }
857
858 void WRTNativeWindow::SetClosable(bool closable) {
859   NOTIMPLEMENTED();
860 }
861
862 bool WRTNativeWindow::IsClosable() {
863   NOTIMPLEMENTED();
864   return true;
865 }
866
867 void WRTNativeWindow::SetAlwaysOnTop(ui::ZOrderLevel z_order,
868                                      const std::string& level,
869                                      int relativeLevel) {
870   NOTIMPLEMENTED();
871 }
872
873 ui::ZOrderLevel WRTNativeWindow::GetZOrderLevel() {
874   NOTIMPLEMENTED();
875   return ui::ZOrderLevel::kNormal;
876 }
877
878 void WRTNativeWindow::Center() {
879   NOTIMPLEMENTED();
880 }
881
882 void WRTNativeWindow::Invalidate() {
883   NOTIMPLEMENTED();
884 }
885
886 void WRTNativeWindow::SetTitle(const std::string& title) {
887   title_ = title;
888   ecore_evas_title_set(platform_canvas, title_.c_str());
889 }
890
891 std::string WRTNativeWindow::GetTitle() {
892   return title_;
893 }
894
895 void WRTNativeWindow::FlashFrame(bool flash) {
896   NOTIMPLEMENTED();
897 }
898
899 void WRTNativeWindow::SetSkipTaskbar(bool skip) {
900   NOTIMPLEMENTED();
901 }
902
903 void WRTNativeWindow::SetExcludedFromShownWindowsMenu(bool excluded) {
904   NOTIMPLEMENTED();
905 }
906
907 bool WRTNativeWindow::IsExcludedFromShownWindowsMenu() {
908   NOTIMPLEMENTED();
909   return false;
910 }
911
912 void WRTNativeWindow::SetSimpleFullScreen(bool simple_fullscreen) {
913   NOTIMPLEMENTED();
914 }
915
916 bool WRTNativeWindow::IsSimpleFullScreen() {
917   NOTIMPLEMENTED();
918   return false;
919 }
920
921 void WRTNativeWindow::SetKiosk(bool kiosk) {
922   NOTIMPLEMENTED();
923 }
924
925 bool WRTNativeWindow::IsKiosk() {
926   NOTIMPLEMENTED();
927   return true;
928 }
929
930 void WRTNativeWindow::SetBackgroundColor(SkColor color) {
931   GetWebContentsViewAura()->SetBackgroundColor(color);
932 }
933
934 SkColor WRTNativeWindow::GetBackgroundColor() {
935   return GetWebContentsViewAura()->GetBackgroundColor();
936 }
937
938 void WRTNativeWindow::SetHasShadow(bool has_shadow) {
939   NOTIMPLEMENTED();
940 }
941
942 bool WRTNativeWindow::HasShadow() {
943   NOTIMPLEMENTED();
944   return true;
945 }
946
947 void WRTNativeWindow::SetOpacity(const double opacity) {
948   NOTIMPLEMENTED();
949 }
950
951 double WRTNativeWindow::GetOpacity() {
952   NOTIMPLEMENTED();
953   return 1.0;
954 }
955
956 void WRTNativeWindow::SetIgnoreMouseEvents(bool ignore, bool forward) {
957   NOTIMPLEMENTED();
958 }
959
960 void WRTNativeWindow::SetContentProtection(bool enable) {
961   NOTIMPLEMENTED();
962 }
963
964 void WRTNativeWindow::AddBrowserView(electron::NativeBrowserView* view) {
965   NOTIMPLEMENTED();
966 }
967
968 void WRTNativeWindow::RemoveBrowserView(electron::NativeBrowserView* view) {
969   NOTIMPLEMENTED();
970 }
971
972 void WRTNativeWindow::SetTopBrowserView(electron::NativeBrowserView* view) {
973   NOTIMPLEMENTED();
974 }
975
976 content::DesktopMediaID WRTNativeWindow::GetDesktopMediaID() const {
977   auto id = static_cast<content::DesktopMediaID::Id>(GetAcceleratedWidget());
978   return content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW, id);
979 }
980
981 gfx::NativeView WRTNativeWindow::GetNativeView() const {
982   return web_contents_->GetNativeView();
983 }
984
985 gfx::NativeWindow WRTNativeWindow::GetNativeWindow() const {
986   return web_contents_->GetTopLevelNativeWindow();
987 }
988
989 gfx::AcceleratedWidget WRTNativeWindow::GetAcceleratedWidget() const {
990   NOTIMPLEMENTED();
991   return gfx::AcceleratedWidget();
992 }
993
994 electron::NativeWindowHandle WRTNativeWindow::GetNativeWindowHandle() const {
995   return GetAcceleratedWidget();
996 }
997
998 void WRTNativeWindow::SetProgressBar(
999     double progress, const ProgressState state) {
1000   NOTIMPLEMENTED();
1001 }
1002
1003 void WRTNativeWindow::SetOverlayIcon(
1004     const gfx::Image& overlay, const std::string& description) {
1005   NOTIMPLEMENTED();
1006 }
1007
1008 // Workspace APIs.
1009 void WRTNativeWindow::SetVisibleOnAllWorkspaces(
1010     bool visible, bool visibleOnFullScreen, bool skipTransformProcessType) {
1011   NOTIMPLEMENTED();
1012 }
1013
1014 bool WRTNativeWindow::IsVisibleOnAllWorkspaces() {
1015   NOTIMPLEMENTED();
1016   return true;
1017 }
1018
1019 // Converts between content bounds and window bounds.
1020 gfx::Rect WRTNativeWindow::ContentBoundsToWindowBounds(
1021     const gfx::Rect& bounds) const {
1022   NOTIMPLEMENTED();
1023   return gfx::Rect();
1024 }
1025
1026 gfx::Rect WRTNativeWindow::WindowBoundsToContentBounds(
1027     const gfx::Rect& bounds) const {
1028   NOTIMPLEMENTED();
1029   return gfx::Rect();
1030 }
1031
1032 void WRTNativeWindow::OnSoftKeyboardChangeEvent(bool value) {
1033   content::RenderFrameHost* rfh = GetRenderFrameHost();
1034   if (!rfh)
1035     return;
1036
1037   std::stringstream script;
1038   script
1039     << "(function(){"
1040     << "var __event = document.createEvent(\"CustomEvent\");\n"
1041     << "var __detail = {};\n"
1042     << "__event.initCustomEvent(\"softkeyboardchange\",true,true,__detail);\n"
1043     << "__event.state = \"" << (value == true ? "on" : "off") << "\";\n"
1044     << "__event.width = " << (value == true ? ime_width : 0) << ";\n"
1045     << "__event.height = " << (value == true ? ime_height : 0) << ";\n"
1046     << "document.dispatchEvent(__event);\n"
1047     << "\n"
1048     << "for (var i=0; i < window.frames.length; i++)\n"
1049     << "{ window.frames[i].document.dispatchEvent(__event); }"
1050     << "})()";
1051   std::string kSoftKeyboardScript = script.str();
1052   std::u16string js_script;
1053   base::UTF8ToUTF16(kSoftKeyboardScript.c_str(), kSoftKeyboardScript.size(),
1054                     &js_script);
1055   rfh->ExecuteJavaScriptWithUserGestureForTests(
1056       js_script, base::NullCallback());
1057 }
1058
1059 void WRTNativeWindow::OnRotaryEvent(RotaryEventType type) {
1060   content::RenderFrameHost* rfh = GetRenderFrameHost();
1061   if (!rfh)
1062     return;
1063
1064   std::stringstream script;
1065   script
1066     << "(function(){"
1067     << "var __event = document.createEvent(\"CustomEvent\");\n"
1068     << "var __detail = {};\n"
1069     << "__event.initCustomEvent(\"rotarydetent\", true, true, __detail);\n"
1070     << "__event.detail.direction = \""
1071     << (type == RotaryEventType::CLOCKWISE ? "CW" : "CCW") << "\";\n"
1072     << "document.dispatchEvent(__event);\n"
1073     << "\n"
1074     << "for (var i=0; i < window.frames.length; i++)\n"
1075     << "{ window.frames[i].document.dispatchEvent(__event); }"
1076     << "})()";
1077   std::string kRotaryEventScript = script.str();
1078   std::u16string js_script;
1079   base::UTF8ToUTF16(kRotaryEventScript.c_str(), kRotaryEventScript.size(),
1080                     &js_script);
1081   rfh->ExecuteJavaScriptWithUserGestureForTests(
1082       js_script, base::NullCallback());
1083 }
1084
1085 std::unique_ptr<views::NonClientFrameView>
1086 WRTNativeWindow::CreateNonClientFrameView(views::Widget* widget) {
1087   return std::make_unique<WRTFrameView>();
1088 }
1089
1090 }  // namespace wrt
1091
1092 namespace electron {
1093
1094 // static
1095 NativeWindow* NativeWindow::Create(const gin_helper::Dictionary& options,
1096                                    NativeWindow* parent) {
1097   return new WRTNativeWindowType(options, parent);
1098 }
1099
1100 }  // namespace electron