1 // Copyright 2019 The Chromium Authors. 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 "components/arc/intent_helper/custom_tab.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/threading/sequenced_task_runner_handle.h"
12 #include "components/exo/shell_surface_util.h"
13 #include "components/exo/surface.h"
14 #include "ui/aura/window.h"
15 #include "ui/aura/window_targeter.h"
16 #include "ui/views/widget/widget.h"
17 #include "ui/views/widget/widget_delegate.h"
18
19 namespace arc {
20
CustomTab(aura::Window * arc_app_window)21 CustomTab::CustomTab(aura::Window* arc_app_window)
22 : arc_app_window_(arc_app_window) {
23 arc_app_window_observer_.Add(arc_app_window_);
24 host_->set_owned_by_client();
25 auto* const widget = views::Widget::GetWidgetForNativeWindow(arc_app_window_);
26 DCHECK(widget);
27 widget->GetContentsView()->AddChildView(host_.get());
28 }
29
30 CustomTab::~CustomTab() = default;
31
Attach(gfx::NativeView view)32 void CustomTab::Attach(gfx::NativeView view) {
33 DCHECK(view);
34 DCHECK(!GetHostView());
35 host_->Attach(view);
36 aura::Window* const container = host_->GetNativeViewContainer();
37 container->SetEventTargeter(std::make_unique<aura::WindowTargeter>());
38 other_windows_observer_.Add(container);
39 EnsureWindowOrders();
40 UpdateHostBounds(arc_app_window_);
41 }
42
GetHostView()43 gfx::NativeView CustomTab::GetHostView() {
44 return host_->native_view();
45 }
46
OnWindowBoundsChanged(aura::Window * window,const gfx::Rect & old_bounds,const gfx::Rect & new_bounds,ui::PropertyChangeReason reason)47 void CustomTab::OnWindowBoundsChanged(aura::Window* window,
48 const gfx::Rect& old_bounds,
49 const gfx::Rect& new_bounds,
50 ui::PropertyChangeReason reason) {
51 if (arc_app_window_observer_.IsObserving(window) &&
52 old_bounds.size() != new_bounds.size()) {
53 UpdateHostBounds(window);
54 }
55 }
56
OnWindowStackingChanged(aura::Window * window)57 void CustomTab::OnWindowStackingChanged(aura::Window* window) {
58 if (window == host_->GetNativeViewContainer() &&
59 !weak_ptr_factory_.HasWeakPtrs()) {
60 // Reordering should happen asynchronously -- some entity (like
61 // views::WindowReorderer) changes the window orders, and then ensures layer
62 // orders later. Changing order here synchronously leads to inconsistent
63 // window/layer ordering and causes weird graphical effects.
64 // TODO(hashimoto): fix the views ordering and remove this handling.
65 base::SequencedTaskRunnerHandle::Get()->PostTask(
66 FROM_HERE, base::BindOnce(&CustomTab::EnsureWindowOrders,
67 weak_ptr_factory_.GetWeakPtr()));
68 }
69 }
70
OnWindowDestroying(aura::Window * window)71 void CustomTab::OnWindowDestroying(aura::Window* window) {
72 if (arc_app_window_observer_.IsObserving(window))
73 arc_app_window_observer_.Remove(window);
74 if (other_windows_observer_.IsObserving(window))
75 other_windows_observer_.Remove(window);
76 }
77
UpdateHostBounds(aura::Window * arc_app_window)78 void CustomTab::UpdateHostBounds(aura::Window* arc_app_window) {
79 DCHECK(arc_app_window);
80 auto* surface = exo::GetShellMainSurface(arc_app_window);
81 if (!surface)
82 return;
83
84 aura::Window* surface_window = surface->window();
85 gfx::Point origin(0, 0);
86 gfx::Point bottom_right(surface_window->bounds().width(),
87 surface_window->bounds().height());
88 ConvertPointFromWindow(surface_window, &origin);
89 ConvertPointFromWindow(surface_window, &bottom_right);
90 host_->SetBounds(origin.x(), origin.y(), bottom_right.x() - origin.x(),
91 bottom_right.y() - origin.y());
92 }
93
EnsureWindowOrders()94 void CustomTab::EnsureWindowOrders() {
95 aura::Window* const container = host_->GetNativeViewContainer();
96 if (container)
97 container->parent()->StackChildAtTop(container);
98 }
99
ConvertPointFromWindow(aura::Window * window,gfx::Point * point)100 void CustomTab::ConvertPointFromWindow(aura::Window* window,
101 gfx::Point* point) {
102 views::Widget* const widget = host_->GetWidget();
103 aura::Window::ConvertPointToTarget(window, widget->GetNativeWindow(), point);
104 views::View::ConvertPointFromWidget(widget->GetContentsView(), point);
105 }
106
107 } // namespace arc
108