| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2009 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/notifications/balloons.h" | 
 |    6  | 
 |    7 #include "base/logging.h" | 
 |    8 #include "base/gfx/rect.h" | 
 |    9 #include "chrome/browser/notifications/balloon_view_win.h" | 
 |   10 #include "chrome/browser/renderer_host/render_view_host.h" | 
 |   11 #include "chrome/browser/renderer_host/render_widget_host_view_win.h" | 
 |   12 #include "chrome/browser/renderer_host/site_instance.h" | 
 |   13 #include "views/window/window_win.h" | 
 |   14  | 
 |   15 namespace { | 
 |   16 // Portion of the screen allotted for notifications. | 
 |   17 // When notification balloons extend over this threshold, no new notifications | 
 |   18 // are shown until some balloons are expired/closed. | 
 |   19 const double kPercentBalloonFillFactor = 0.7; | 
 |   20  | 
 |   21 // Allow at least this number of balloons on the screen. | 
 |   22 const int kMinAllowedBalloonCount = 2; | 
 |   23  | 
 |   24 void GetMainScreenWorkArea(gfx::Rect* bounds) { | 
 |   25   DCHECK(bounds); | 
 |   26   RECT work_area = {0}; | 
 |   27   if (::SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0)) { | 
 |   28     bounds->SetRect(work_area.left, | 
 |   29                     work_area.top, | 
 |   30                     work_area.right, | 
 |   31                     work_area.bottom); | 
 |   32   } else { | 
 |   33     // If failed to call SystemParametersInfo for some reason, we simply get the | 
 |   34     // full screen size as an alternative. | 
 |   35     bounds->SetRect(0, | 
 |   36                     0, | 
 |   37                     ::GetSystemMetrics(SM_CXSCREEN) - 1, | 
 |   38                     ::GetSystemMetrics(SM_CYSCREEN) - 1); | 
 |   39   } | 
 |   40 } | 
 |   41  | 
 |   42 double GetSystemFontScaleFactor() { | 
 |   43   return 1.0; | 
 |   44 } | 
 |   45 } // namespace | 
 |   46  | 
 |   47 BalloonCollection::BalloonCollection() { | 
 |   48 } | 
 |   49  | 
 |   50 void BalloonCollection::AddObserver(BalloonCollectionObserver* observer) { | 
 |   51   DCHECK(observer); | 
 |   52   observers_.push_back(observer); | 
 |   53   observer->OnBalloonSpaceChanged(); | 
 |   54 } | 
 |   55  | 
 |   56 bool BalloonCollection::HasSpace() const { | 
 |   57   if (count() < kMinAllowedBalloonCount) { | 
 |   58     return true; | 
 |   59   } | 
 |   60  | 
 |   61   int max_balloon_length = 0; | 
 |   62   int total_length = 0; | 
 |   63   layout_.GetMaxLengths(&max_balloon_length, &total_length); | 
 |   64  | 
 |   65   int current_max_length = max_balloon_length  * count(); | 
 |   66   int max_allowed_length = static_cast<int>(total_length * | 
 |   67                                             kPercentBalloonFillFactor); | 
 |   68   return current_max_length < max_allowed_length - max_balloon_length; | 
 |   69 } | 
 |   70  | 
 |   71 void BalloonCollection::Add(const Notification& notification, | 
 |   72                             Profile* profile, | 
 |   73                             SiteInstance* site_instance) { | 
 |   74   Balloon* new_balloon = MakeBalloon(notification, profile, site_instance); | 
 |   75   gfx::Size size(layout_.min_balloon_width(), layout_.min_balloon_height()); | 
 |   76   new_balloon->SetSize(size); | 
 |   77   balloons_.push_back(new_balloon); | 
 |   78   gfx::Point origin = layout_.GetOrigin(); | 
 |   79   for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { | 
 |   80     gfx::Point upper_left = layout_.NextPosition((*it)->size(), &origin); | 
 |   81     (*it)->SetPosition(upper_left, false); | 
 |   82   } | 
 |   83   new_balloon->Show(); | 
 |   84   notification.display(); | 
 |   85   for (BalloonObservers::iterator it = observers_.begin();  | 
 |   86        it != observers_.end();  | 
 |   87        ++it) { | 
 |   88     (*it)->OnBalloonSpaceChanged(); | 
 |   89   }   | 
 |   90 } | 
 |   91  | 
 |   92 void BalloonCollection::OnBalloonClosed(Balloon* source) { | 
 |   93   source->notification().close(true); | 
 |   94  | 
 |   95   for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { | 
 |   96     if (*it == source) { | 
 |   97       balloons_.erase(it); | 
 |   98       break; | 
 |   99     } | 
 |  100   } | 
 |  101  | 
 |  102   gfx::Point origin = layout_.GetOrigin(); | 
 |  103   for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { | 
 |  104     gfx::Point upper_left = layout_.NextPosition((*it)->size(), &origin); | 
 |  105     (*it)->SetPosition(upper_left, true); | 
 |  106   } | 
 |  107 } | 
 |  108  | 
 |  109 void BalloonCollection::ShowAll() { | 
 |  110 } | 
 |  111  | 
 |  112 void BalloonCollection::HideAll() { | 
 |  113 } | 
 |  114  | 
 |  115 Balloon::Balloon(const Notification& notification, | 
 |  116                  Profile* profile, | 
 |  117                  SiteInstance* site_instance, | 
 |  118                  BalloonCloseListener* listener) | 
 |  119     : profile_(profile), | 
 |  120       site_instance_(site_instance), | 
 |  121       notification_(notification), | 
 |  122       close_listener_(listener) { | 
 |  123 } | 
 |  124  | 
 |  125 Balloon::~Balloon() { | 
 |  126 } | 
 |  127  | 
 |  128 void Balloon::Show() { | 
 |  129   if (!balloon_view_.get()) { | 
 |  130     balloon_view_.reset(new BalloonView()); | 
 |  131     balloon_view_->Show(this); | 
 |  132   } | 
 |  133 } | 
 |  134  | 
 |  135  | 
 |  136 void Balloon::Close() { | 
 |  137   if (close_listener_) { | 
 |  138     close_listener_->OnBalloonClosed(this); | 
 |  139   } | 
 |  140 } | 
 |  141  | 
 |  142 void Balloon::SetPosition(const gfx::Point& upper_left, bool reposition) { | 
 |  143   position_ = upper_left; | 
 |  144   if (reposition && balloon_view_.get()) { | 
 |  145     balloon_view_->RepositionToBalloon(); | 
 |  146   } | 
 |  147 } | 
 |  148  | 
 |  149 void Balloon::SetSize(const gfx::Size& size) { | 
 |  150   size_ = size; | 
 |  151 } | 
 |  152  | 
 |  153 const gfx::Point& Balloon::position() const { | 
 |  154   return position_; | 
 |  155 } | 
 |  156  | 
 |  157 const gfx::Size& Balloon::size() const { | 
 |  158   return size_; | 
 |  159 } | 
 |  160  | 
 |  161 BalloonCollection::Layout::Placement BalloonCollection::Layout::placement_ = | 
 |  162     BalloonCollection::Layout::VERTICALLY_FROM_BOTTOM_RIGHT; | 
 |  163  | 
 |  164 BalloonCollection::Layout::Layout() | 
 |  165     : font_scale_factor_(1.0) { | 
 |  166   RefreshSystemMetrics(); | 
 |  167 } | 
 |  168  | 
 |  169 // Scale the size to count in the system font factor | 
 |  170 int BalloonCollection::Layout::ScaleSize(int size) const { | 
 |  171   return static_cast<int>(size * font_scale_factor_); | 
 |  172 } | 
 |  173  | 
 |  174 int BalloonCollection::Layout::min_balloon_width() const { | 
 |  175   return ScaleSize(kBalloonMinWidth); | 
 |  176 } | 
 |  177  | 
 |  178 int BalloonCollection::Layout::max_balloon_width() const { | 
 |  179   return ScaleSize(kBalloonMaxWidth); | 
 |  180 } | 
 |  181  | 
 |  182 int BalloonCollection::Layout::min_balloon_height() const { | 
 |  183   return ScaleSize(kBalloonMinHeight); | 
 |  184 } | 
 |  185  | 
 |  186 int BalloonCollection::Layout::max_balloon_height() const { | 
 |  187   return ScaleSize(kBalloonMaxHeight); | 
 |  188 } | 
 |  189  | 
 |  190 gfx::Point BalloonCollection::Layout::GetOrigin() const { | 
 |  191   int x = 0; | 
 |  192   int y = 0; | 
 |  193   switch (placement_) { | 
 |  194     case HORIZONTALLY_FROM_BOTTOM_LEFT: | 
 |  195       x = work_area_.x(); | 
 |  196       y = work_area_.bottom(); | 
 |  197       break; | 
 |  198     case HORIZONTALLY_FROM_BOTTOM_RIGHT: | 
 |  199       x = work_area_.right(); | 
 |  200       y = work_area_.bottom(); | 
 |  201       break; | 
 |  202     case VERTICALLY_FROM_TOP_RIGHT: | 
 |  203       x = work_area_.right(); | 
 |  204       y = work_area_.y(); | 
 |  205       break; | 
 |  206     case VERTICALLY_FROM_BOTTOM_RIGHT: | 
 |  207       x = work_area_.right(); | 
 |  208       y = work_area_.bottom(); | 
 |  209       break; | 
 |  210     default: | 
 |  211       NOTREACHED(); | 
 |  212       break; | 
 |  213   } | 
 |  214   return gfx::Point(x, y); | 
 |  215 } | 
 |  216  | 
 |  217 gfx::Point BalloonCollection::Layout::NextPosition( | 
 |  218     const gfx::Size& balloon_size, | 
 |  219     gfx::Point* origin) const { | 
 |  220   DCHECK(origin); | 
 |  221  | 
 |  222   int x = 0; | 
 |  223   int y = 0; | 
 |  224   switch (placement_) { | 
 |  225     case HORIZONTALLY_FROM_BOTTOM_LEFT: | 
 |  226       x = origin->x(); | 
 |  227       y = origin->y() - balloon_size.height(); | 
 |  228       origin->set_x(origin->x() + balloon_size.width()); | 
 |  229       break; | 
 |  230     case HORIZONTALLY_FROM_BOTTOM_RIGHT: | 
 |  231       origin->set_x(origin->x() - balloon_size.width()); | 
 |  232       x = origin->x(); | 
 |  233       y = origin->y() - balloon_size.height(); | 
 |  234       break; | 
 |  235     case VERTICALLY_FROM_TOP_RIGHT: | 
 |  236       x = origin->x() - balloon_size.width(); | 
 |  237       y = origin->y(); | 
 |  238       origin->set_y(origin->y() + balloon_size.height()); | 
 |  239       break; | 
 |  240     case VERTICALLY_FROM_BOTTOM_RIGHT: | 
 |  241       origin->set_y(origin->y() - balloon_size.height()); | 
 |  242       x = origin->x() - balloon_size.width(); | 
 |  243       y = origin->y(); | 
 |  244       break; | 
 |  245     default: | 
 |  246       NOTREACHED(); | 
 |  247       break; | 
 |  248   } | 
 |  249   return gfx::Point(x, y); | 
 |  250 } | 
 |  251  | 
 |  252 bool BalloonCollection::Layout::RefreshSystemMetrics() { | 
 |  253   bool changed = false; | 
 |  254  | 
 |  255   gfx::Rect new_work_area(work_area_.x(), work_area_.y(), | 
 |  256                           work_area_.width(), work_area_.height()); | 
 |  257   GetMainScreenWorkArea(&new_work_area); | 
 |  258   if (!work_area_.Equals(new_work_area)) { | 
 |  259     work_area_.SetRect(new_work_area.x(), new_work_area.y(), | 
 |  260                        new_work_area.width(), new_work_area.height()); | 
 |  261     changed = true; | 
 |  262   } | 
 |  263  | 
 |  264   double new_font_scale_factor = font_scale_factor_; | 
 |  265   new_font_scale_factor = GetSystemFontScaleFactor(); | 
 |  266   if (font_scale_factor_ != new_font_scale_factor) { | 
 |  267     font_scale_factor_ = new_font_scale_factor; | 
 |  268     changed = true; | 
 |  269   } | 
 |  270   return changed; | 
 |  271 } | 
 |  272  | 
 |  273 const void BalloonCollection::Layout::GetMaxLengths( | 
 |  274     int* max_balloon_length, | 
 |  275     int* total_length) const { | 
 |  276   DCHECK(max_balloon_length && total_length); | 
 |  277  | 
 |  278   switch (placement_) { | 
 |  279     case HORIZONTALLY_FROM_BOTTOM_LEFT: | 
 |  280     case HORIZONTALLY_FROM_BOTTOM_RIGHT: | 
 |  281       *total_length = work_area_.width(); | 
 |  282       *max_balloon_length = max_balloon_width(); | 
 |  283       break; | 
 |  284     case VERTICALLY_FROM_TOP_RIGHT: | 
 |  285     case VERTICALLY_FROM_BOTTOM_RIGHT: | 
 |  286       *total_length = work_area_.height(); | 
 |  287       *max_balloon_length = max_balloon_height(); | 
 |  288       break; | 
 |  289     default: | 
 |  290       NOTREACHED(); | 
 |  291       break; | 
 |  292   } | 
 |  293 } | 
 |  294  | 
| OLD | NEW |