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

ash / system / tray / tray_bubble_wrapper.cc [blame]

// Copyright 2012 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/system/tray/tray_bubble_wrapper.h"
#include <memory>

#include "ash/app_list/app_list_controller_impl.h"
#include "ash/shell.h"
#include "ash/system/tray/tray_background_view.h"
#include "ash/system/tray/tray_bubble_view.h"
#include "ash/system/tray/tray_event_filter.h"
#include "ui/aura/window.h"
#include "ui/display/screen.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/transient_window_manager.h"

namespace ash {

TrayBubbleWrapper::TrayBubbleWrapper(TrayBackgroundView* tray,
                                     bool event_handling)
    : tray_(tray), event_handling_(event_handling) {}

TrayBubbleWrapper::~TrayBubbleWrapper() {
  if (bubble_widget_) {
    // A bubble might have transcient child open (i.e. the network info bubble
    // in the network detailed view of QS). Thus, we need to remove all those
    // transient children before destruction.
    auto* transient_manager = ::wm::TransientWindowManager::GetOrCreate(
        bubble_widget_->GetNativeWindow());
    while (transient_manager &&
           !transient_manager->transient_children().empty()) {
      transient_manager->RemoveTransientChild(
          transient_manager->transient_children().back());
    }
    bubble_widget_->RemoveObserver(this);
    bubble_widget_->Close();
  }
  CHECK(!TrayBubbleBase::IsInObserverList());
}

void TrayBubbleWrapper::ShowBubble(
    std::unique_ptr<TrayBubbleView> bubble_view) {
  // We must ensure `ShowBubble` is only called when there is no existing
  // `bubble_widget_`.
  DCHECK(!bubble_widget_);

  bubble_view_ = bubble_view.get();
  bubble_widget_ =
      views::BubbleDialogDelegateView::CreateBubble(std::move(bubble_view));
  bubble_widget_->AddObserver(this);

  TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
  bubble_view_->InitializeAndShowBubble();

  // We need to explicitly dismiss app list bubble here due to b/1186479.
  if (!display::Screen::GetScreen()->InTabletMode()) {
    Shell::Get()->app_list_controller()->DismissAppList();
  }

  if (event_handling_) {
    tray_event_filter_ = std::make_unique<TrayEventFilter>(
        bubble_widget_, bubble_view_, /*tray_button=*/tray_);
  }
}

TrayBackgroundView* TrayBubbleWrapper::GetTray() const {
  return tray_;
}

TrayBubbleView* TrayBubbleWrapper::GetBubbleView() const {
  return bubble_view_;
}

views::Widget* TrayBubbleWrapper::GetBubbleWidget() const {
  return bubble_widget_;
}

void TrayBubbleWrapper::OnWidgetDestroying(views::Widget* widget) {
  CHECK_EQ(bubble_widget_, widget);
  bubble_widget_->RemoveObserver(this);
  bubble_widget_ = nullptr;

  tray_->HideBubbleWithView(bubble_view_);  // May destroy |bubble_view_|
}

}  // namespace ash