Index: chrome/browser/ui/views/message_center/web_notification_tray_win.cc |
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray_win.cc b/chrome/browser/ui/views/message_center/web_notification_tray_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2d24d3d91382f2bfec0b475f7114addfdd9fa279 |
--- /dev/null |
+++ b/chrome/browser/ui/views/message_center/web_notification_tray_win.cc |
@@ -0,0 +1,253 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ui/views/message_center/web_notification_tray_win.h" |
+ |
+#include "base/memory/singleton.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/status_icons/status_icon.h" |
+#include "chrome/browser/status_icons/status_tray.h" |
+#include "chrome/browser/ui/message_center/message_center_util.h" |
+#include "chrome/browser/ui/views/message_center/notification_bubble_wrapper_win.h" |
+#include "chrome/browser/ui/views/status_icons/status_icon_win.h" |
+#include "grit/theme_resources.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/base/win/hwnd_util.h" |
+#include "ui/gfx/image/image_skia_operations.h" |
+#include "ui/gfx/screen.h" |
+#include "ui/message_center/message_bubble_base.h" |
+#include "ui/message_center/message_center_bubble.h" |
+#include "ui/message_center/message_center_tray.h" |
+#include "ui/message_center/message_popup_bubble.h" |
+#include "ui/views/widget/widget.h" |
+ |
+namespace { |
+ |
+// Tray constants |
+const int kPaddingFromLeftEdgeOfSystemTrayBottomAlignment = 8; |
+ |
+gfx::Rect GetCornerAnchorRect(gfx::Size preferred_size) { |
+ gfx::Screen* screen = gfx::Screen::GetNativeScreen(); |
+ gfx::Point cursor = screen->GetCursorScreenPoint(); |
+ gfx::Rect rect = screen->GetPrimaryDisplay().work_area(); |
+ rect.Inset(10, 5); |
+ gfx::Point bottom_right( |
+ rect.bottom_right().x() - preferred_size.width() / 2, |
+ rect.bottom_right().y()); |
+ return gfx::Rect(bottom_right, gfx::Size()); |
+} |
+ |
+// GetMouseAnchorRect returns a rectangle that is near the cursor point, but |
+// whose behavior depends on where the Windows taskbar is. If it is on the |
+// top or bottom of the screen, we want the arrow to touch the edge of the |
+// taskbar directly above or below the mouse pointer and within the work area. |
+// Otherwise, position the anchor on the mouse cursor directly. |
+gfx::Rect GetMouseAnchorRect() { |
+ gfx::Screen* screen = gfx::Screen::GetNativeScreen(); |
+ gfx::Point cursor = screen->GetCursorScreenPoint(); |
+ gfx::Rect rect = screen->GetPrimaryDisplay().bounds(); |
+ gfx::Rect work_area = screen->GetPrimaryDisplay().work_area(); |
+ |
+ // Inset the rectangle by the taskbar width if it is on top or bottom. |
+ rect.set_y(work_area.y()); |
+ rect.set_height(work_area.height()); |
+ |
+ rect.Inset(kPaddingFromLeftEdgeOfSystemTrayBottomAlignment, 0); |
+ |
+ // Want to find a mouse point that is on the mouse cursor, unless the mouse is |
+ // over the start menu and the start menu is on the top or bottom. |
+ gfx::Rect mouse_anchor_rect(gfx::BoundingRect(cursor, rect.bottom_right())); |
+ mouse_anchor_rect.set_height(0); |
+ if (!rect.Contains(cursor)) |
+ mouse_anchor_rect.AdjustToFit(rect); |
+ mouse_anchor_rect.set_width(0); |
+ return mouse_anchor_rect; |
+} |
+ |
+gfx::ImageSkia GetIcon(bool has_unread_notifications) { |
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
+ gfx::ImageSkia* icon = |
+ rb.GetImageSkiaNamed(IDR_ALLOWED_NOTIFICATION); |
+ if (has_unread_notifications) |
+ return *icon; |
+ return gfx::ImageSkiaOperations::CreateTransparentImage(*icon, .5); |
+} |
+ |
+} // namespace |
+ |
+#if defined(ENABLE_MESSAGE_CENTER) |
+ |
+namespace chrome { |
+ |
+// static |
+ui::MessageCenterTrayDelegate* GetMessageCenterTray() { |
+ return ui::WebNotificationTrayWin::GetInstance(); |
+} |
+ |
+} // namespace chrome |
+ |
+#endif |
+ |
+ |
+namespace ui { |
+ |
+// TODO(dewittj): Determine a better ownership relationship for this. |
+WebNotificationTrayWin* WebNotificationTrayWin::GetInstance() { |
+ return Singleton<WebNotificationTrayWin>::get(); |
+} |
+ |
+WebNotificationTrayWin::WebNotificationTrayWin() |
+ : status_icon_(NULL), |
+ message_center_visible_(false) { |
+ message_center_tray_ = new MessageCenterTray(this); |
+ message_center_tray_->AddObserver(this); |
+ StatusTray* status_tray = g_browser_process->status_tray(); |
+ status_icon_ = status_tray->CreateStatusIcon(); |
+ status_icon_->AddObserver(this); |
+ status_icon_->SetImage( |
+ GetIcon(message_center()->UnreadNotificationCount() > 0)); |
+} |
+ |
+WebNotificationTrayWin::~WebNotificationTrayWin() { |
+ message_center_tray_->RemoveObserver(this); |
+ if (g_browser_process) { // We are destroyed after g_browser_process. |
+ status_icon_->RemoveObserver(this); |
+ StatusTray * status_tray = g_browser_process->status_tray(); |
+ status_tray->RemoveStatusIcon(status_icon_); |
+ } |
+ status_icon_ = NULL; |
+} |
+ |
+message_center::MessageCenter* WebNotificationTrayWin::message_center() { |
+ return message_center_tray_->message_center(); |
+} |
+ |
+bool WebNotificationTrayWin::ShowPopups( |
+ message_center::MessageBubbleBase* bubble) { |
+ if (!CanShowPopups()) |
+ return false; |
+ popup_bubble_.reset(new internal::NotificationBubbleWrapperWin( |
+ this, |
+ bubble, |
+ views::TrayBubbleView::ANCHOR_TYPE_BUBBLE)); |
+ return true; |
+} |
+void WebNotificationTrayWin::HidePopups() { |
+ popup_bubble_.reset(); |
+} |
+bool WebNotificationTrayWin::ShowMessageCenter( |
+ message_center::MessageBubbleBase* bubble) { |
+ gfx::Screen* screen = gfx::Screen::GetNativeScreen(); |
+ gfx::Rect work_area = screen->GetPrimaryDisplay().work_area(); |
+ gfx::Point work_area_center = work_area.CenterPoint(); |
+ gfx::Point anchor_center = message_center_anchor_rect_.CenterPoint(); |
+ int max_height = 0; |
+ if (work_area_center < anchor_center) |
+ max_height = anchor_center.y() - work_area.origin().y(); |
+ else |
+ max_height = work_area.bottom() - message_center_anchor_rect_.bottom(); |
+ bubble->SetMaxHeight(max_height); |
+ |
+ message_center_bubble_.reset(new internal::NotificationBubbleWrapperWin( |
+ this, |
+ bubble, |
+ views::TrayBubbleView::ANCHOR_TYPE_TRAY)); |
+ return true; |
+} |
+ |
+void WebNotificationTrayWin::HideMessageCenter() { |
+ message_center_bubble_.reset(); |
+} |
+ |
+void WebNotificationTrayWin::UpdateMessageCenter() { |
+ if (message_center_bubble_.get()) |
+ message_center_bubble_->bubble()->ScheduleUpdate(); |
+} |
+ |
+void WebNotificationTrayWin::UpdatePopups() { |
+ if (popup_bubble_.get()) |
+ popup_bubble_->bubble()->ScheduleUpdate(); |
+}; |
+ |
+ |
+ |
+void WebNotificationTrayWin::OnMessageCenterTrayChanged() { |
+ bool has_unread_notifications = |
+ message_center()->UnreadNotificationCount() > 0; |
+ status_icon_->SetImage(GetIcon(has_unread_notifications)); |
+} |
+ |
+gfx::Rect WebNotificationTrayWin::GetAnchorRect( |
+ gfx::Size preferred_size, |
+ views::TrayBubbleView::AnchorType anchor_type, |
+ views::TrayBubbleView::AnchorAlignment anchor_alignment) { |
+ // |message_center_visible_| is set before the bubble is actually rendered, |
+ // so the flag can be used to determine which anchor to use. |
+ if (anchor_type == views::TrayBubbleView::ANCHOR_TYPE_TRAY) { |
+ return message_center_anchor_rect_; |
+ } |
+ return GetCornerAnchorRect(preferred_size); |
+} |
+ |
+bool WebNotificationTrayWin::CanShowPopups() { |
+ // TODO(dewittj): This will eventually depend on whether quiet mode is active. |
+ return true; |
+} |
+ |
+views::TrayBubbleView::AnchorAlignment |
+WebNotificationTrayWin::GetAnchorAlignment() { |
+ gfx::Screen* screen = gfx::Screen::GetNativeScreen(); |
+ // TODO(dewittj): It's possible GetPrimaryDisplay is wrong. |
+ gfx::Rect screen_bounds = screen->GetPrimaryDisplay().bounds(); |
+ gfx::Rect work_area = screen->GetPrimaryDisplay().work_area(); |
+ |
+ if (work_area.height() < screen_bounds.height()) |
+ return views::TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM; |
+ if (work_area.x() > screen_bounds.x()) |
+ return views::TrayBubbleView::ANCHOR_ALIGNMENT_LEFT; |
+ return views::TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT; |
+} |
+ |
+gfx::NativeView WebNotificationTrayWin::GetBubbleWindowContainer() { |
+ return NULL; |
+} |
+ |
+ |
+void WebNotificationTrayWin::OnStatusIconClicked() { |
+ UpdateAnchorRect(); |
+ message_center_tray_->ToggleMessageCenterBubble(); |
+} |
+ |
+void WebNotificationTrayWin::HideBubbleWithView( |
+ const views::TrayBubbleView* bubble_view) { |
+ if (message_center_bubble_.get() && |
+ bubble_view == message_center_bubble_->bubble_view()) { |
+ message_center_tray_->HideMessageCenterBubble(); |
+ } else if (popup_bubble_.get() && |
+ bubble_view == popup_bubble_->bubble_view()) { |
+ message_center_tray_->HidePopupBubble(); |
+ } |
+} |
+ |
+void WebNotificationTrayWin::UpdateAnchorRect() { |
+ message_center_anchor_rect_ = GetMouseAnchorRect(); |
+} |
+ |
+message_center::MessageCenterBubble* |
+WebNotificationTrayWin::GetMessageCenterBubbleForTest() { |
+ if (!message_center_bubble_.get()) |
+ return NULL; |
+ return static_cast<message_center::MessageCenterBubble*>( |
+ message_center_bubble_->bubble()); |
+} |
+ |
+message_center::MessagePopupBubble* |
+WebNotificationTrayWin::GetPopupBubbleForTest() { |
+ if (!popup_bubble_.get()) |
+ return NULL; |
+ return static_cast<message_center::MessagePopupBubble*>( |
+ popup_bubble_->bubble()); |
+} |
+ |
+} // namespace ui |