1 // Copyright 2014 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 "ui/message_center/views/desktop_message_popup_collection.h"
6
7 #include "ui/display/display.h"
8 #include "ui/display/screen.h"
9 #include "ui/gfx/geometry/rect.h"
10 #include "ui/message_center/public/cpp/message_center_constants.h"
11
12 namespace message_center {
13
DesktopMessagePopupCollection()14 DesktopMessagePopupCollection::DesktopMessagePopupCollection()
15 : alignment_(POPUP_ALIGNMENT_BOTTOM | POPUP_ALIGNMENT_RIGHT),
16 primary_display_id_(display::kInvalidDisplayId),
17 screen_(nullptr) {}
18
~DesktopMessagePopupCollection()19 DesktopMessagePopupCollection::~DesktopMessagePopupCollection() {
20 if (screen_)
21 screen_->RemoveObserver(this);
22 }
23
StartObserving(display::Screen * screen)24 void DesktopMessagePopupCollection::StartObserving(display::Screen* screen) {
25 if (screen_ || !screen)
26 return;
27
28 screen_ = screen;
29 screen_->AddObserver(this);
30 display::Display display = screen_->GetPrimaryDisplay();
31 primary_display_id_ = display.id();
32 RecomputeAlignment(display);
33 }
34
GetToastOriginX(const gfx::Rect & toast_bounds) const35 int DesktopMessagePopupCollection::GetToastOriginX(
36 const gfx::Rect& toast_bounds) const {
37 if (IsFromLeft())
38 return work_area_.x() + kMarginBetweenPopups;
39 return work_area_.right() - kMarginBetweenPopups - toast_bounds.width();
40 }
41
GetBaseline() const42 int DesktopMessagePopupCollection::GetBaseline() const {
43 return IsTopDown() ? work_area_.y() + kMarginBetweenPopups
44 : work_area_.bottom() - kMarginBetweenPopups;
45 }
46
GetWorkArea() const47 gfx::Rect DesktopMessagePopupCollection::GetWorkArea() const {
48 return work_area_;
49 }
50
IsTopDown() const51 bool DesktopMessagePopupCollection::IsTopDown() const {
52 return (alignment_ & POPUP_ALIGNMENT_TOP) != 0;
53 }
54
IsFromLeft() const55 bool DesktopMessagePopupCollection::IsFromLeft() const {
56 return (alignment_ & POPUP_ALIGNMENT_LEFT) != 0;
57 }
58
RecomputeAlignment(const display::Display & display)59 bool DesktopMessagePopupCollection::RecomputeAlignment(
60 const display::Display& display) {
61 if (work_area_ == display.work_area())
62 return false;
63
64 work_area_ = display.work_area();
65
66 // If the taskbar is at the top, render notifications top down. Some platforms
67 // like Gnome can have taskbars at top and bottom. In this case it's more
68 // likely that the systray is on the top one.
69 alignment_ = work_area_.y() > display.bounds().y() ? POPUP_ALIGNMENT_TOP
70 : POPUP_ALIGNMENT_BOTTOM;
71
72 // If the taskbar is on the left show the notifications on the left. Otherwise
73 // show it on right since it's very likely that the systray is on the right if
74 // the taskbar is on the top or bottom.
75 // Since on some platforms like Ubuntu Unity there's also a launcher along
76 // with a taskbar (panel), we need to check that there is really nothing at
77 // the top before concluding that the taskbar is at the left.
78 alignment_ |= (work_area_.x() > display.bounds().x() &&
79 work_area_.y() == display.bounds().y())
80 ? POPUP_ALIGNMENT_LEFT
81 : POPUP_ALIGNMENT_RIGHT;
82
83 return true;
84 }
85
ConfigureWidgetInitParamsForContainer(views::Widget * widget,views::Widget::InitParams * init_params)86 void DesktopMessagePopupCollection::ConfigureWidgetInitParamsForContainer(
87 views::Widget* widget,
88 views::Widget::InitParams* init_params) {
89 // Do nothing, which will use the default container.
90 }
91
IsPrimaryDisplayForNotification() const92 bool DesktopMessagePopupCollection::IsPrimaryDisplayForNotification() const {
93 return true;
94 }
95
BlockForMixedFullscreen(const Notification & notification) const96 bool DesktopMessagePopupCollection::BlockForMixedFullscreen(
97 const Notification& notification) const {
98 // Always return false. Notifications for fullscreen will be blocked by
99 // chrome/browser/notifications/fullscreen_notification_blocker.
100 return false;
101 }
102
103 // Anytime the display configuration changes, we need to recompute the alignment
104 // on the primary display. But, we get different events on different platforms.
105 // On Windows, for example, when switching from a laptop display to an external
106 // monitor, we get a OnDisplayMetricsChanged() event. On Linux, we get a
107 // OnDisplayRemoved() and a OnDisplayAdded() instead. In order to account for
108 // these slightly different abstractions, we update on every event.
UpdatePrimaryDisplay()109 void DesktopMessagePopupCollection::UpdatePrimaryDisplay() {
110 display::Display primary_display = screen_->GetPrimaryDisplay();
111 if (primary_display.id() != primary_display_id_) {
112 primary_display_id_ = primary_display.id();
113 if (RecomputeAlignment(primary_display))
114 ResetBounds();
115 }
116 }
117
OnDisplayAdded(const display::Display & added_display)118 void DesktopMessagePopupCollection::OnDisplayAdded(
119 const display::Display& added_display) {
120 // The added display could be the new primary display.
121 UpdatePrimaryDisplay();
122 }
123
OnDisplayRemoved(const display::Display & removed_display)124 void DesktopMessagePopupCollection::OnDisplayRemoved(
125 const display::Display& removed_display) {
126 // The removed display may have been the primary display.
127 UpdatePrimaryDisplay();
128 }
129
OnDisplayMetricsChanged(const display::Display & display,uint32_t metrics)130 void DesktopMessagePopupCollection::OnDisplayMetricsChanged(
131 const display::Display& display,
132 uint32_t metrics) {
133 // Set to kInvalidDisplayId so the alignment is updated regardless of whether
134 // the primary display actually changed.
135 primary_display_id_ = display::kInvalidDisplayId;
136 UpdatePrimaryDisplay();
137 }
138
139 } // namespace message_center
140