Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: chrome/browser/notifications/balloon_collection_impl.cc

Issue 8503037: Fix the problem that notifications and panels overlap. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/notifications/balloon_collection_impl.h" 5 #include "chrome/browser/notifications/balloon_collection_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "chrome/browser/notifications/balloon.h" 10 #include "chrome/browser/notifications/balloon.h"
11 #include "chrome/browser/notifications/balloon_host.h" 11 #include "chrome/browser/notifications/balloon_host.h"
12 #include "chrome/browser/notifications/notification.h" 12 #include "chrome/browser/notifications/notification.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/panels/panel_manager.h"
15 #include "chrome/browser/ui/panels/panel.h"
13 #include "chrome/browser/ui/window_sizer.h" 16 #include "chrome/browser/ui/window_sizer.h"
17 #include "chrome/common/chrome_notification_types.h"
18 #include "content/public/browser/notification_registrar.h"
19 #include "content/public/browser/notification_service.h"
14 #include "ui/gfx/rect.h" 20 #include "ui/gfx/rect.h"
15 #include "ui/gfx/size.h" 21 #include "ui/gfx/size.h"
16 22
17 namespace { 23 namespace {
18 24
19 // Portion of the screen allotted for notifications. When notification balloons 25 // Portion of the screen allotted for notifications. When notification balloons
20 // extend over this, no new notifications are shown until some are closed. 26 // extend over this, no new notifications are shown until some are closed.
21 const double kPercentBalloonFillFactor = 0.7; 27 const double kPercentBalloonFillFactor = 0.7;
22 28
23 // Allow at least this number of balloons on the screen. 29 // Allow at least this number of balloons on the screen.
24 const int kMinAllowedBalloonCount = 2; 30 const int kMinAllowedBalloonCount = 2;
25 31
26 // Delay from the mouse leaving the balloon collection before 32 // Delay from the mouse leaving the balloon collection before
27 // there is a relayout, in milliseconds. 33 // there is a relayout, in milliseconds.
28 const int kRepositionDelay = 300; 34 const int kRepositionDelay = 300;
29 35
30 } // namespace 36 } // namespace
31 37
32 BalloonCollectionImpl::BalloonCollectionImpl() 38 BalloonCollectionImpl::BalloonCollectionImpl()
33 #if USE_OFFSETS 39 #if USE_OFFSETS
34 : ALLOW_THIS_IN_INITIALIZER_LIST(reposition_factory_(this)), 40 : ALLOW_THIS_IN_INITIALIZER_LIST(reposition_factory_(this)),
35 added_as_message_loop_observer_(false) 41 added_as_message_loop_observer_(false)
36 #endif 42 #endif
37 { 43 {
44 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
45 content::NotificationService::AllSources());
46 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
47 content::NotificationService::AllSources());
48 registrar_.Add(this, chrome::NOTIFICATION_PANEL_CHANGED_BOUNDS,
49 content::NotificationService::AllSources());
38 50
39 SetPositionPreference(BalloonCollection::DEFAULT_POSITION); 51 SetPositionPreference(BalloonCollection::DEFAULT_POSITION);
40 } 52 }
41 53
42 BalloonCollectionImpl::~BalloonCollectionImpl() { 54 BalloonCollectionImpl::~BalloonCollectionImpl() {
43 } 55 }
44 56
45 void BalloonCollectionImpl::Add(const Notification& notification, 57 void BalloonCollectionImpl::Add(const Notification& notification,
46 Profile* profile) { 58 Profile* profile) {
47 Balloon* new_balloon = MakeBalloon(notification, profile); 59 Balloon* new_balloon = MakeBalloon(notification, profile);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 158
147 // This is used only for testing. 159 // This is used only for testing.
148 if (!on_collection_changed_callback_.is_null()) 160 if (!on_collection_changed_callback_.is_null())
149 on_collection_changed_callback_.Run(); 161 on_collection_changed_callback_.Run();
150 } 162 }
151 163
152 const BalloonCollection::Balloons& BalloonCollectionImpl::GetActiveBalloons() { 164 const BalloonCollection::Balloons& BalloonCollectionImpl::GetActiveBalloons() {
153 return base_.balloons(); 165 return base_.balloons();
154 } 166 }
155 167
168 void BalloonCollectionImpl::Observe(
169 int type,
170 const content::NotificationSource& source,
171 const content::NotificationDetails& details) {
172 switch (type) {
173 case chrome::NOTIFICATION_BROWSER_WINDOW_READY:
174 case chrome::NOTIFICATION_BROWSER_CLOSED: {
175 Browser* browser = content::Source<Browser>(source).ptr();
176 if (browser->is_type_panel())
177 PositionBalloons(true);
178 break;
179 }
180 case chrome::NOTIFICATION_PANEL_CHANGED_BOUNDS:
181 PositionBalloons(true);
182 break;
183 default:
184 NOTREACHED();
185 break;
186 }
187 }
188
156 void BalloonCollectionImpl::PositionBalloonsInternal(bool reposition) { 189 void BalloonCollectionImpl::PositionBalloonsInternal(bool reposition) {
157 const Balloons& balloons = base_.balloons(); 190 const Balloons& balloons = base_.balloons();
158 191
159 layout_.RefreshSystemMetrics(); 192 layout_.RefreshSystemMetrics();
160 gfx::Point origin = layout_.GetLayoutOrigin(); 193 gfx::Point origin = layout_.GetLayoutOrigin();
161 for (Balloons::const_iterator it = balloons.begin(); 194 for (Balloons::const_iterator it = balloons.begin();
162 it != balloons.end(); 195 it != balloons.end();
163 ++it) { 196 ++it) {
164 gfx::Point upper_left = layout_.NextPosition((*it)->GetViewSize(), &origin); 197 gfx::Point upper_left = layout_.NextPosition((*it)->GetViewSize(), &origin);
165 (*it)->SetPosition(upper_left, reposition); 198 (*it)->SetPosition(upper_left, reposition);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 reposition_factory_.GetWeakPtr()), 257 reposition_factory_.GetWeakPtr()),
225 kRepositionDelay); 258 kRepositionDelay);
226 } 259 }
227 } else { 260 } else {
228 // Mouse moved back into the region. Cancel the reposition. 261 // Mouse moved back into the region. Cancel the reposition.
229 reposition_factory_.InvalidateWeakPtrs(); 262 reposition_factory_.InvalidateWeakPtrs();
230 } 263 }
231 } 264 }
232 #endif 265 #endif
233 266
234 BalloonCollectionImpl::Layout::Layout() : placement_(INVALID) { 267 BalloonCollectionImpl::Layout::Layout()
268 : placement_(INVALID),
269 panel_height_base_(0) {
235 RefreshSystemMetrics(); 270 RefreshSystemMetrics();
236 } 271 }
237 272
238 void BalloonCollectionImpl::Layout::GetMaxLinearSize(int* max_balloon_size, 273 void BalloonCollectionImpl::Layout::GetMaxLinearSize(int* max_balloon_size,
239 int* total_size) const { 274 int* total_size) const {
240 DCHECK(max_balloon_size && total_size); 275 DCHECK(max_balloon_size && total_size);
241 276
242 // All placement schemes are vertical, so we only care about height. 277 // All placement schemes are vertical, so we only care about height.
243 *total_size = work_area_.height(); 278 *total_size = work_area_.height();
244 *max_balloon_size = max_balloon_height(); 279 *max_balloon_size = max_balloon_height();
245 } 280 }
246 281
247 gfx::Point BalloonCollectionImpl::Layout::GetLayoutOrigin() const { 282 gfx::Point BalloonCollectionImpl::Layout::GetLayoutOrigin() const {
248 int x = 0; 283 int x = 0;
249 int y = 0; 284 int y = 0;
250 switch (placement_) { 285 switch (placement_) {
251 case VERTICALLY_FROM_TOP_LEFT: 286 case VERTICALLY_FROM_TOP_LEFT:
252 x = work_area_.x() + HorizontalEdgeMargin(); 287 x = work_area_.x() + HorizontalEdgeMargin();
253 y = work_area_.y() + VerticalEdgeMargin(); 288 y = work_area_.y() + VerticalEdgeMargin();
254 break; 289 break;
255 case VERTICALLY_FROM_TOP_RIGHT: 290 case VERTICALLY_FROM_TOP_RIGHT:
256 x = work_area_.right() - HorizontalEdgeMargin(); 291 x = work_area_.right() - HorizontalEdgeMargin();
257 y = work_area_.y() + VerticalEdgeMargin(); 292 y = work_area_.y() + VerticalEdgeMargin();
258 break; 293 break;
259 case VERTICALLY_FROM_BOTTOM_LEFT: 294 case VERTICALLY_FROM_BOTTOM_LEFT:
260 x = work_area_.x() + HorizontalEdgeMargin(); 295 x = work_area_.x() + HorizontalEdgeMargin();
261 y = work_area_.bottom() - VerticalEdgeMargin(); 296 y = work_area_.bottom() - VerticalEdgeMargin();
262 break; 297 break;
263 case VERTICALLY_FROM_BOTTOM_RIGHT: 298 case VERTICALLY_FROM_BOTTOM_RIGHT: {
264 x = work_area_.right() - HorizontalEdgeMargin(); 299 x = work_area_.right() - HorizontalEdgeMargin();
265 y = work_area_.bottom() - VerticalEdgeMargin(); 300 // For this placement, balloon needs to stay on top of right-most panels
301 // to avoid overlapping.
302 y = work_area_.bottom() - VerticalEdgeMargin() - panel_height_base_;
266 break; 303 break;
304 }
267 default: 305 default:
268 NOTREACHED(); 306 NOTREACHED();
269 break; 307 break;
270 } 308 }
271 return gfx::Point(x, y); 309 return gfx::Point(x, y);
272 } 310 }
273 311
274 gfx::Point BalloonCollectionImpl::Layout::NextPosition( 312 gfx::Point BalloonCollectionImpl::Layout::NextPosition(
275 const gfx::Size& balloon_size, 313 const gfx::Size& balloon_size,
276 gfx::Point* position_iterator) const { 314 gfx::Point* position_iterator) const {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 gfx::Size BalloonCollectionImpl::Layout::ConstrainToSizeLimits( 394 gfx::Size BalloonCollectionImpl::Layout::ConstrainToSizeLimits(
357 const gfx::Size& size) { 395 const gfx::Size& size) {
358 // restrict to the min & max sizes 396 // restrict to the min & max sizes
359 return gfx::Size( 397 return gfx::Size(
360 std::max(min_balloon_width(), 398 std::max(min_balloon_width(),
361 std::min(max_balloon_width(), size.width())), 399 std::min(max_balloon_width(), size.width())),
362 std::max(min_balloon_height(), 400 std::max(min_balloon_height(),
363 std::min(max_balloon_height(), size.height()))); 401 std::min(max_balloon_height(), size.height())));
364 } 402 }
365 403
404 int BalloonCollectionImpl::Layout::GetPanelHeightBase() const {
Dmitry Titov 2011/11/09 03:09:57 If we add a method on PanelManager to pull this he
jianli 2011/11/09 19:04:40 Indeed we don't need to expose 'horizontal_spacing
405 // The height base is computed based on the maximum height of the right-most
406 // panels that could overlap with the balloon.
407 int height_base = 0;
408 const PanelManager::Panels& panels = PanelManager::GetInstance()->panels();
409 for (PanelManager::Panels::const_iterator iter = panels.begin();
410 iter != panels.end(); ++iter) {
411 if ((*iter)->GetBounds().right() + PanelManager::horizontal_spacing() <=
412 work_area_.right() - max_balloon_width())
413 break;
414 int current_height = (*iter)->GetBounds().height();
415 if (current_height > height_base)
416 height_base = current_height;
417 }
418 return height_base;
419 }
420
366 bool BalloonCollectionImpl::Layout::RefreshSystemMetrics() { 421 bool BalloonCollectionImpl::Layout::RefreshSystemMetrics() {
367 bool changed = false; 422 bool changed = false;
368 423
369 #if defined(OS_MACOSX) 424 #if defined(OS_MACOSX)
370 gfx::Rect new_work_area = GetMacWorkArea(); 425 gfx::Rect new_work_area = GetMacWorkArea();
371 #else 426 #else
372 scoped_ptr<WindowSizer::MonitorInfoProvider> info_provider( 427 scoped_ptr<WindowSizer::MonitorInfoProvider> info_provider(
373 WindowSizer::CreateDefaultMonitorInfoProvider()); 428 WindowSizer::CreateDefaultMonitorInfoProvider());
374 gfx::Rect new_work_area = info_provider->GetPrimaryMonitorWorkArea(); 429 gfx::Rect new_work_area = info_provider->GetPrimaryMonitorWorkArea();
375 #endif 430 #endif
376 if (!work_area_.Equals(new_work_area)) { 431 if (!work_area_.Equals(new_work_area)) {
377 work_area_.SetRect(new_work_area.x(), new_work_area.y(), 432 work_area_.SetRect(new_work_area.x(), new_work_area.y(),
378 new_work_area.width(), new_work_area.height()); 433 new_work_area.width(), new_work_area.height());
379 changed = true; 434 changed = true;
380 } 435 }
381 436
437 panel_height_base_ = GetPanelHeightBase();
438
382 return changed; 439 return changed;
383 } 440 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698