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