OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ash/system/tray/system_tray.h" | 5 #include "ash/system/tray/system_tray.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/shell/panel_window.h" | 8 #include "ash/shell/panel_window.h" |
9 #include "ash/shell_window_ids.h" | 9 #include "ash/shell_window_ids.h" |
10 #include "ash/system/audio/tray_volume.h" | 10 #include "ash/system/audio/tray_volume.h" |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 } | 236 } |
237 | 237 |
238 void SystemTray::AddTrayItem(SystemTrayItem* item) { | 238 void SystemTray::AddTrayItem(SystemTrayItem* item) { |
239 items_.push_back(item); | 239 items_.push_back(item); |
240 | 240 |
241 SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate(); | 241 SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate(); |
242 views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus()); | 242 views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus()); |
243 if (tray_item) { | 243 if (tray_item) { |
244 tray_container_->AddChildViewAt(tray_item, 0); | 244 tray_container_->AddChildViewAt(tray_item, 0); |
245 PreferredSizeChanged(); | 245 PreferredSizeChanged(); |
| 246 tray_item_map_[item] = tray_item; |
246 } | 247 } |
247 } | 248 } |
248 | 249 |
249 void SystemTray::RemoveTrayItem(SystemTrayItem* item) { | 250 void SystemTray::RemoveTrayItem(SystemTrayItem* item) { |
250 NOTIMPLEMENTED(); | 251 NOTIMPLEMENTED(); |
251 } | 252 } |
252 | 253 |
253 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) { | 254 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) { |
254 ShowItems(items_.get(), false, true, creation_type); | 255 ShowDefaultViewWithOffset(creation_type, -1); |
255 } | 256 } |
256 | 257 |
257 void SystemTray::ShowDetailedView(SystemTrayItem* item, | 258 void SystemTray::ShowDetailedView(SystemTrayItem* item, |
258 int close_delay, | 259 int close_delay, |
259 bool activate, | 260 bool activate, |
260 BubbleCreationType creation_type) { | 261 BubbleCreationType creation_type) { |
261 std::vector<SystemTrayItem*> items; | 262 std::vector<SystemTrayItem*> items; |
262 items.push_back(item); | 263 items.push_back(item); |
263 ShowItems(items, true, activate, creation_type); | 264 ShowItems(items, true, activate, creation_type, GetTrayXOffset(item)); |
264 bubble_->StartAutoCloseTimer(close_delay); | 265 bubble_->StartAutoCloseTimer(close_delay); |
265 } | 266 } |
266 | 267 |
267 void SystemTray::ShowNotificationView(SystemTrayItem* item) { | 268 void SystemTray::ShowNotificationView(SystemTrayItem* item) { |
268 if (std::find(notification_items_.begin(), notification_items_.end(), item) | 269 if (std::find(notification_items_.begin(), notification_items_.end(), item) |
269 != notification_items_.end()) | 270 != notification_items_.end()) |
270 return; | 271 return; |
271 notification_items_.push_back(item); | 272 notification_items_.push_back(item); |
272 UpdateNotificationBubble(); | 273 UpdateNotificationBubble(); |
273 } | 274 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 NOTREACHED(); | 329 NOTREACHED(); |
329 } | 330 } |
330 } | 331 } |
331 | 332 |
332 void SystemTray::SetPaintsBackground( | 333 void SystemTray::SetPaintsBackground( |
333 bool value, | 334 bool value, |
334 internal::BackgroundAnimator::ChangeType change_type) { | 335 internal::BackgroundAnimator::ChangeType change_type) { |
335 hide_background_animator_.SetPaintsBackground(value, change_type); | 336 hide_background_animator_.SetPaintsBackground(value, change_type); |
336 } | 337 } |
337 | 338 |
| 339 int SystemTray::GetTrayXOffset(SystemTrayItem* item) const { |
| 340 std::map<SystemTrayItem*, views::View*>::const_iterator it = |
| 341 tray_item_map_.find(item); |
| 342 if (it == tray_item_map_.end()) |
| 343 return -1; |
| 344 |
| 345 const views::View* item_view = it->second; |
| 346 gfx::Rect item_bounds = item_view->bounds(); |
| 347 if (!item_bounds.IsEmpty()) { |
| 348 int x_offset = item_bounds.x() + item_bounds.width() / 2; |
| 349 return base::i18n::IsRTL() ? x_offset : tray_container_->width() - x_offset; |
| 350 } |
| 351 |
| 352 // The bounds of item could be still empty. It could happen in the case that |
| 353 // the view appears for the first time in the current session, because the |
| 354 // bounds is not calculated yet. In that case, we want to guess the offset |
| 355 // from the position of its parent. |
| 356 int x_offset = 0; |
| 357 for (int i = 0; i < tray_container_->child_count(); ++i) { |
| 358 const views::View* child = tray_container_->child_at(i); |
| 359 if (child == item_view) |
| 360 return base::i18n::IsRTL() ? |
| 361 x_offset : tray_container_->width() - x_offset; |
| 362 |
| 363 if (!child->visible()) |
| 364 continue; |
| 365 x_offset = child->bounds().right(); |
| 366 } |
| 367 |
| 368 return -1; |
| 369 } |
| 370 |
| 371 void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type, |
| 372 int arrow_offset) { |
| 373 ShowItems(items_.get(), false, true, creation_type, arrow_offset); |
| 374 } |
| 375 |
338 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, | 376 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, |
339 bool detailed, | 377 bool detailed, |
340 bool can_activate, | 378 bool can_activate, |
341 BubbleCreationType creation_type) { | 379 BubbleCreationType creation_type, |
| 380 int arrow_offset) { |
342 // Destroy any existing bubble and create a new one. | 381 // Destroy any existing bubble and create a new one. |
343 SystemTrayBubble::BubbleType bubble_type = detailed ? | 382 SystemTrayBubble::BubbleType bubble_type = detailed ? |
344 SystemTrayBubble::BUBBLE_TYPE_DETAILED : | 383 SystemTrayBubble::BUBBLE_TYPE_DETAILED : |
345 SystemTrayBubble::BUBBLE_TYPE_DEFAULT; | 384 SystemTrayBubble::BUBBLE_TYPE_DEFAULT; |
346 if (bubble_.get() && creation_type == BUBBLE_USE_EXISTING) { | 385 if (bubble_.get() && creation_type == BUBBLE_USE_EXISTING) { |
347 bubble_->UpdateView(items, bubble_type); | 386 bubble_->UpdateView(items, bubble_type); |
348 } else { | 387 } else { |
349 bubble_.reset(new SystemTrayBubble(this, items, bubble_type)); | 388 bubble_.reset(new SystemTrayBubble(this, items, bubble_type)); |
350 ash::SystemTrayDelegate* delegate = | 389 ash::SystemTrayDelegate* delegate = |
351 ash::Shell::GetInstance()->tray_delegate(); | 390 ash::Shell::GetInstance()->tray_delegate(); |
352 bubble_->InitView(tray_container_, SystemTrayBubble::ANCHOR_TYPE_TRAY, | 391 views::View* anchor = tray_container_; |
353 can_activate, delegate->GetUserLoginStatus()); | 392 SystemTrayBubble::InitParams init_params( |
| 393 SystemTrayBubble::ANCHOR_TYPE_TRAY); |
| 394 init_params.anchor = anchor; |
| 395 init_params.can_activate = can_activate; |
| 396 init_params.login_status = delegate->GetUserLoginStatus(); |
| 397 if (arrow_offset >= 0) |
| 398 init_params.arrow_offset = arrow_offset; |
| 399 bubble_->InitView(init_params); |
354 } | 400 } |
355 // If we have focus the shelf should be visible and we need to continue | 401 // If we have focus the shelf should be visible and we need to continue |
356 // showing the shelf when the popup is shown. | 402 // showing the shelf when the popup is shown. |
357 if (GetWidget()->IsActive()) | 403 if (GetWidget()->IsActive()) |
358 should_show_launcher_ = true; | 404 should_show_launcher_ = true; |
359 UpdateNotificationBubble(); // State changed, re-create notifications. | 405 UpdateNotificationBubble(); // State changed, re-create notifications. |
360 } | 406 } |
361 | 407 |
362 void SystemTray::UpdateNotificationBubble() { | 408 void SystemTray::UpdateNotificationBubble() { |
363 // Only show the notification buble if we have notifications and we are not | 409 // Only show the notification buble if we have notifications and we are not |
364 // showing the default bubble. | 410 // showing the default bubble. |
365 if (notification_items_.empty() || | 411 if (notification_items_.empty() || |
366 (bubble_.get() && | 412 (bubble_.get() && |
367 bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { | 413 bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { |
368 notification_bubble_.reset(); | 414 notification_bubble_.reset(); |
369 return; | 415 return; |
370 } | 416 } |
371 notification_bubble_.reset( | 417 notification_bubble_.reset( |
372 new SystemTrayBubble(this, notification_items_, | 418 new SystemTrayBubble(this, notification_items_, |
373 SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION)); | 419 SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION)); |
374 views::View* anchor; | 420 views::View* anchor; |
375 SystemTrayBubble::AnchorType anchor_type; | 421 SystemTrayBubble::AnchorType anchor_type; |
376 if (bubble_.get()) { | 422 if (bubble_.get()) { |
377 anchor = bubble_->bubble_view(); | 423 anchor = bubble_->bubble_view(); |
378 anchor_type = SystemTrayBubble::ANCHOR_TYPE_BUBBLE; | 424 anchor_type = SystemTrayBubble::ANCHOR_TYPE_BUBBLE; |
379 } else { | 425 } else { |
380 anchor = tray_container_; | 426 anchor = tray_container_; |
381 anchor_type = SystemTrayBubble::ANCHOR_TYPE_TRAY; | 427 anchor_type = SystemTrayBubble::ANCHOR_TYPE_TRAY; |
382 } | 428 } |
383 notification_bubble_->InitView( | 429 SystemTrayBubble::InitParams init_params(anchor_type); |
384 anchor, anchor_type, | 430 init_params.anchor = anchor; |
385 false /* can_activate */, | 431 init_params.login_status = |
386 ash::Shell::GetInstance()->tray_delegate()->GetUserLoginStatus()); | 432 ash::Shell::GetInstance()->tray_delegate()->GetUserLoginStatus(); |
| 433 int arrow_offset = GetTrayXOffset(notification_items_[0]); |
| 434 if (arrow_offset >= 0) |
| 435 init_params.arrow_offset = arrow_offset; |
| 436 notification_bubble_->InitView(init_params); |
387 } | 437 } |
388 | 438 |
389 void SystemTray::UpdateNotificationAnchor() { | 439 void SystemTray::UpdateNotificationAnchor() { |
390 if (!notification_bubble_.get()) | 440 if (!notification_bubble_.get()) |
391 return; | 441 return; |
392 notification_bubble_->bubble_view()->UpdateAnchor(); | 442 notification_bubble_->bubble_view()->UpdateAnchor(); |
393 // Ensure that the notification buble is above the launcher/status area. | 443 // Ensure that the notification buble is above the launcher/status area. |
394 notification_bubble_->bubble_view()->GetWidget()->StackAtTop(); | 444 notification_bubble_->bubble_view()->GetWidget()->StackAtTop(); |
395 } | 445 } |
396 | 446 |
397 bool SystemTray::PerformAction(const views::Event& event) { | 447 bool SystemTray::PerformAction(const views::Event& event) { |
398 // If we're already showing the default view, hide it; otherwise, show it | 448 // If we're already showing the default view, hide it; otherwise, show it |
399 // (and hide any popup that's currently shown). | 449 // (and hide any popup that's currently shown). |
400 if (bubble_.get() && | 450 if (bubble_.get() && |
401 bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT) { | 451 bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT) { |
402 bubble_->Close(); | 452 bubble_->Close(); |
403 } else { | 453 } else { |
404 ShowDefaultView(BUBBLE_CREATE_NEW); | 454 int arrow_offset = -1; |
| 455 if (event.IsMouseEvent() || event.IsTouchEvent()) { |
| 456 const views::LocatedEvent& located_event = |
| 457 static_cast<const views::LocatedEvent&>(event); |
| 458 arrow_offset = base::i18n::IsRTL() ? |
| 459 located_event.x() : tray_container_->width() - located_event.x(); |
| 460 } |
| 461 ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset); |
405 } | 462 } |
406 return true; | 463 return true; |
407 } | 464 } |
408 | 465 |
409 void SystemTray::OnMouseEntered(const views::MouseEvent& event) { | 466 void SystemTray::OnMouseEntered(const views::MouseEvent& event) { |
410 should_show_launcher_ = true; | 467 should_show_launcher_ = true; |
411 hover_background_animator_.SetPaintsBackground(true, | 468 hover_background_animator_.SetPaintsBackground(true, |
412 internal::BackgroundAnimator::CHANGE_ANIMATE); | 469 internal::BackgroundAnimator::CHANGE_ANIMATE); |
413 } | 470 } |
414 | 471 |
(...skipping 25 matching lines...) Expand all Loading... |
440 canvas->DrawFocusRect(tray_container_->bounds()); | 497 canvas->DrawFocusRect(tray_container_->bounds()); |
441 } | 498 } |
442 | 499 |
443 void SystemTray::UpdateBackground(int alpha) { | 500 void SystemTray::UpdateBackground(int alpha) { |
444 background_->set_alpha(hide_background_animator_.alpha() + | 501 background_->set_alpha(hide_background_animator_.alpha() + |
445 hover_background_animator_.alpha()); | 502 hover_background_animator_.alpha()); |
446 SchedulePaint(); | 503 SchedulePaint(); |
447 } | 504 } |
448 | 505 |
449 } // namespace ash | 506 } // namespace ash |
OLD | NEW |