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