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