1 // Copyright 2018 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 "chrome/browser/ui/views/media_router/web_contents_display_observer_view.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "chrome/browser/ui/browser_list.h"
11 #include "content/public/browser/web_contents.h"
12 #include "ui/display/screen.h"
13 #include "ui/views/widget/widget.h"
14
15 namespace media_router {
16
17 // static
Create(content::WebContents * web_contents,base::RepeatingClosure callback)18 std::unique_ptr<WebContentsDisplayObserver> WebContentsDisplayObserver::Create(
19 content::WebContents* web_contents,
20 base::RepeatingClosure callback) {
21 return std::make_unique<WebContentsDisplayObserverView>(web_contents,
22 std::move(callback));
23 }
24
WebContentsDisplayObserverView(content::WebContents * web_contents,base::RepeatingClosure callback)25 WebContentsDisplayObserverView::WebContentsDisplayObserverView(
26 content::WebContents* web_contents,
27 base::RepeatingClosure callback)
28 : web_contents_(web_contents),
29 widget_(views::Widget::GetWidgetForNativeWindow(
30 web_contents->GetTopLevelNativeWindow())),
31 callback_(std::move(callback)) {
32 // |widget_| may be null in tests.
33 if (widget_) {
34 display_ = GetDisplayNearestWidget();
35 widget_->AddObserver(this);
36 }
37 BrowserList::AddObserver(this);
38 }
39
~WebContentsDisplayObserverView()40 WebContentsDisplayObserverView::~WebContentsDisplayObserverView() {
41 if (widget_)
42 widget_->RemoveObserver(this);
43 BrowserList::RemoveObserver(this);
44 CHECK(!IsInObserverList());
45 }
46
OnBrowserSetLastActive(Browser * browser)47 void WebContentsDisplayObserverView::OnBrowserSetLastActive(Browser* browser) {
48 // This gets called when a browser tab detaches from a window or gets merged
49 // into another window. We update the widget to observe, if necessary.
50 // If |web_contents_| or |widget_| is null, then we no longer have WebContents
51 // to observe.
52 if (!web_contents_ || !widget_)
53 return;
54
55 views::Widget* new_widget = views::Widget::GetWidgetForNativeWindow(
56 web_contents_->GetTopLevelNativeWindow());
57 if (new_widget != widget_) {
58 widget_->RemoveObserver(this);
59 widget_ = new_widget;
60 if (widget_) {
61 widget_->AddObserver(this);
62 CheckForDisplayChange();
63 }
64 }
65 }
66
OnWidgetClosing(views::Widget * widget)67 void WebContentsDisplayObserverView::OnWidgetClosing(views::Widget* widget) {
68 if (widget_)
69 widget_->RemoveObserver(this);
70 widget_ = nullptr;
71 }
72
OnWidgetBoundsChanged(views::Widget * widget,const gfx::Rect & new_bounds)73 void WebContentsDisplayObserverView::OnWidgetBoundsChanged(
74 views::Widget* widget,
75 const gfx::Rect& new_bounds) {
76 CheckForDisplayChange();
77 }
78
GetCurrentDisplay() const79 const display::Display& WebContentsDisplayObserverView::GetCurrentDisplay()
80 const {
81 return display_;
82 }
83
WebContentsDestroyed()84 void WebContentsDisplayObserverView::WebContentsDestroyed() {
85 web_contents_ = nullptr;
86 }
87
CheckForDisplayChange()88 void WebContentsDisplayObserverView::CheckForDisplayChange() {
89 display::Display new_display = GetDisplayNearestWidget();
90 if (new_display.id() == display_.id())
91 return;
92
93 display_ = new_display;
94 callback_.Run();
95 }
96
GetDisplayNearestWidget() const97 display::Display WebContentsDisplayObserverView::GetDisplayNearestWidget()
98 const {
99 return display::Screen::GetScreen()->GetDisplayNearestWindow(
100 widget_->GetNativeWindow());
101 }
102
103 } // namespace media_router
104