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