system_tray.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/ash_switches.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shelf/shelf_layout_manager.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell/panel_window.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell_window_ids.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/bluetooth/tray_bluetooth.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/brightness/tray_brightness.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/date/tray_date.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/drive/tray_drive.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/ime/tray_ime.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/locale/tray_locale.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/logout_button/tray_logout_button.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/monitor/tray_monitor.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/session_length_limit/tray_session_length_limit.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/status_area_widget.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_item.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/tray_bubble_wrapper.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/tray_constants.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray_accessibility.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray_caps_lock.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray_update.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/user/login_status.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/user/tray_user.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/timer.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ash_strings.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/events/event_constants.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_util.h" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/border.h" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/label.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/box_layout.h" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/fill_layout.h" 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view.h" 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ash/system/chromeos/audio/tray_audio.h" 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/chromeos/enterprise/tray_enterprise.h" 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ash/system/chromeos/managed/tray_locally_managed_user.h" 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/chromeos/network/tray_network.h" 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/chromeos/network/tray_sms.h" 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/chromeos/network/tray_vpn.h" 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/system/chromeos/power/tray_power.h" 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/chromeos/screen_security/screen_capture_tray_item.h" 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/chromeos/screen_security/screen_share_tray_item.h" 5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/system/chromeos/settings/tray_settings.h" 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/chromeos/tray_display.h" 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using views::TrayBubbleView; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The minimum width of the system tray menu width. 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMinimumSystemTrayMenuWidth = 300; 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instances for a bubble. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SystemBubbleWrapper { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Takes ownership of |bubble|. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit SystemBubbleWrapper(internal::SystemTrayBubble* bubble) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : bubble_(bubble) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes the bubble view and creates |bubble_wrapper_|. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void InitView(TrayBackgroundView* tray, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* anchor, 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView::InitParams* init_params) { 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(anchor); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user::LoginStatus login_status = 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus(); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bubble_->InitView(anchor, login_status, init_params); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bubble_wrapper_.reset( 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new internal::TrayBubbleWrapper(tray, bubble_->bubble_view())); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convenience accessors: 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTrayBubble* bubble() const { return bubble_.get(); } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTrayBubble::BubbleType bubble_type() const { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bubble_->bubble_type(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); } 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<internal::SystemTrayBubble> bubble_; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace internal 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SystemTray 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using internal::SystemTrayBubble; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemTray::SystemTray(internal::StatusAreaWidget* status_area_widget) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : internal::TrayBackgroundView(status_area_widget), 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) items_(), 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_bubble_height_(0), 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hide_notifications_(false) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetContentsBackground(); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemTray::~SystemTray() { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy any child views that might have back pointers before ~View(). 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_.reset(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_.reset(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<SystemTrayItem*>::iterator it = items_.begin(); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != items_.end(); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*it)->DestroyTrayView(); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SystemTray::InitializeTrayItems(SystemTrayDelegate* delegate) { 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) internal::TrayBackgroundView::Initialize(); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CreateItems(delegate); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SystemTray::CreateItems(SystemTrayDelegate* delegate) { 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if !defined(OS_WIN) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TraySessionLengthLimit(this)); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayLogoutButton(this)); 14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // In multi-profile user mode we can have multiple user tiles. 14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ash::Shell* shell = ash::Shell::GetInstance(); 14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int maximum_user_profiles = 14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) shell->delegate()->IsMultiProfilesEnabled() ? 14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers() : 14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 0; 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Note: We purposely use one more item then logged in users to account for 14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // the additional separator. 15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (int i = 0; i <= maximum_user_profiles; i++) 15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddTrayItem(new internal::TrayUser(this, i)); 15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayEnterprise(this)); 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AddTrayItem(new internal::TrayLocallyManagedUser(this)); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayIME(this)); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tray_accessibility_ = new internal::TrayAccessibility(this); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(tray_accessibility_); 16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(OS_CHROMEOS) 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayPower(this)); 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayNetwork(this)); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayVPN(this)); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TraySms(this)); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if !defined(OS_WIN) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayBluetooth(this)); 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayDrive(this)); 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayLocale(this)); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayDisplay(this)); 176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AddTrayItem(new internal::ScreenCaptureTrayItem(this)); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AddTrayItem(new internal::ScreenShareTrayItem(this)); 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AddTrayItem(new internal::TrayAudio(this)); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if !defined(OS_WIN) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayBrightness(this)); 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayCapsLock(this)); 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(OS_CHROMEOS) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TraySettings(this)); 18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayUpdate(this)); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayDate(this)); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add memory monitor if enabled. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine* cmd = CommandLine::ForCurrentProcess(); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cmd->HasSwitch(ash::switches::kAshEnableMemoryMonitor)) 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddTrayItem(new internal::TrayMonitor(this)); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetVisible(ash::Shell::GetInstance()->system_tray_delegate()-> 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetTrayVisibilityOnStartup()); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::AddTrayItem(SystemTrayItem* item) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) items_.push_back(item); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate(); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus()); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->UpdateAfterShelfAlignmentChange(shelf_alignment()); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tray_item) { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tray_container()->AddChildViewAt(tray_item, 0); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreferredSizeChanged(); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tray_item_map_[item] = tray_item; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::RemoveTrayItem(SystemTrayItem* item) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTIMPLEMENTED(); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowDefaultView(BubbleCreationType creation_type) { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShowDefaultViewWithOffset(creation_type, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView::InitParams::kArrowDefaultOffset); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowDetailedView(SystemTrayItem* item, 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int close_delay, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool activate, 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleCreationType creation_type) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<SystemTrayItem*> items; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) items.push_back(item); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShowItems(items, true, activate, creation_type, GetTrayXOffset(item)); 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (system_bubble_) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) system_bubble_->bubble()->StartAutoCloseTimer(close_delay); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::SetDetailedViewCloseDelay(int close_delay) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED)) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->StartAutoCloseTimer(close_delay); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideDetailedView(SystemTrayItem* item) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item != detailed_item_) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroySystemBubble(); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateNotificationBubble(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowNotificationView(SystemTrayItem* item) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (std::find(notification_items_.begin(), notification_items_.end(), item) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) != notification_items_.end()) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_items_.push_back(item); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateNotificationBubble(); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideNotificationView(SystemTrayItem* item) { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<SystemTrayItem*>::iterator found_iter = 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(notification_items_.begin(), notification_items_.end(), item); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (found_iter == notification_items_.end()) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_items_.erase(found_iter); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only update the notification bubble if visible (i.e. don't create one). 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (notification_bubble_) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateNotificationBubble(); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::UpdateAfterLoginStatusChange(user::LoginStatus login_status) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroySystemBubble(); 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) UpdateNotificationBubble(); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<SystemTrayItem*>::iterator it = items_.begin(); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != items_.end(); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*it)->UpdateAfterLoginStatusChange(login_status); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetVisible(true); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreferredSizeChanged(); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<SystemTrayItem*>::iterator it = items_.begin(); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != items_.end(); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*it)->UpdateAfterShelfAlignmentChange(alignment); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::SetHideNotifications(bool hide_notifications) { 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (notification_bubble_) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_->bubble()->SetVisible(!hide_notifications); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hide_notifications_ = hide_notifications; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::ShouldShowLauncher() const { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return system_bubble_.get() && system_bubble_->bubble()->ShouldShowLauncher(); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::HasSystemBubble() const { 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return system_bubble_.get() != NULL; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SystemTray::HasNotificationBubble() const { 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return notification_bubble_.get() != NULL; 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)internal::SystemTrayBubble* SystemTray::GetSystemBubble() { 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!system_bubble_) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return system_bubble_->bubble(); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::IsAnyBubbleVisible() const { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((system_bubble_.get() && 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->IsVisible()) || 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (notification_bubble_.get() && 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_->bubble()->IsVisible())); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::IsMouseInNotificationBubble() const { 320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!notification_bubble_) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return notification_bubble_->bubble_view()->GetBoundsInScreen().Contains( 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Shell::GetScreen()->GetCursorScreenPoint()); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool SystemTray::CloseSystemBubble() const { 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!system_bubble_) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->Close(); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SystemTray::CloseNotificationBubbleForTest() const { 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!notification_bubble_) 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification_bubble_->bubble()->Close(); 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Private methods. 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type != SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return system_bubble_.get() && system_bubble_->bubble_type() == type; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::DestroySystemBubble() { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_.reset(); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) detailed_item_ = NULL; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::DestroyNotificationBubble() { 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_.reset(); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_area_widget()->SetHideWebNotifications(false); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SystemTray::GetTrayXOffset(SystemTrayItem* item) const { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't attempt to align the arrow if the shelf is on the left or right. 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM && 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shelf_alignment() != SHELF_ALIGNMENT_TOP) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TrayBubbleView::InitParams::kArrowDefaultOffset; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<SystemTrayItem*, views::View*>::const_iterator it = 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tray_item_map_.find(item); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == tray_item_map_.end()) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TrayBubbleView::InitParams::kArrowDefaultOffset; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const views::View* item_view = it->second; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item_view->bounds().IsEmpty()) { 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The bounds of item could be still empty if it does not have a visible 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tray view. In that case, use the default (minimum) offset. 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TrayBubbleView::InitParams::kArrowDefaultOffset; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point point(item_view->width() / 2, 0); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPointToWidget(item_view, &point); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return point.x(); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type, 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int arrow_offset) { 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShowItems(items_.get(), false, true, creation_type, arrow_offset); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool detailed, 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool can_activate, 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleCreationType creation_type, 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int arrow_offset) { 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy any existing bubble and create a new one. 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTrayBubble::BubbleType bubble_type = detailed ? 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTrayBubble::BUBBLE_TYPE_DETAILED : 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTrayBubble::BUBBLE_TYPE_DEFAULT; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy the notification bubble here so that it doesn't get rebuilt 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // while we add items to the main bubble_ (e.g. in HideNotificationView). 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_.reset(); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) { 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->UpdateView(items, bubble_type); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The menu width is fixed, and it is a per language setting. 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int menu_width = std::max(kMinimumSystemTrayMenuWidth, 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Shell::GetInstance()->system_tray_delegate()->GetSystemTrayMenuWidth()); 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY, 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAnchorAlignment(), 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) menu_width, 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kTrayPopupMaxWidth); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.can_activate = can_activate; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (detailed) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the case where a volume control or brightness control bubble 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is created. 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.max_height = default_bubble_height_; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.arrow_color = kBackgroundColor; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) init_params.arrow_color = kHeaderBackgroundColor; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.arrow_offset = arrow_offset; 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // For Volume and Brightness we don't want to show an arrow when 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // they are shown in a bubble by themselves. 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) init_params.arrow_paint_type = views::BubbleBorder::PAINT_NORMAL; 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (items.size() == 1 && items[0]->ShouldHideArrow()) 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) init_params.arrow_paint_type = views::BubbleBorder::PAINT_TRANSPARENT; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_.reset(new internal::SystemBubbleWrapper(bubble)); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->InitView(this, tray_container(), &init_params); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save height of default view for creating detailed views directly. 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!detailed) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_bubble_height_ = system_bubble_->bubble_view()->height(); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (detailed && items.size() > 0) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) detailed_item_ = items[0]; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) detailed_item_ = NULL; 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateNotificationBubble(); // State changed, re-create notifications. 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_area_widget()->SetHideWebNotifications(true); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetShelfLayoutManager()->UpdateAutoHideState(); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::UpdateNotificationBubble() { 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only show the notification buble if we have notifications. 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (notification_items_.empty()) { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroyNotificationBubble(); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy the existing bubble before constructing a new one. 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_.reset(); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTrayBubble* notification_bubble; 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification_bubble = new SystemTrayBubble( 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, notification_items_, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* anchor; 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView::AnchorType anchor_type; 456868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Tray items might want to show notifications while we are creating and 457868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // initializing the |system_bubble_| - but it might not be fully initialized 458868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // when coming here - this would produce a crashed like crbug.com/247416. 459868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // As such we check the existence of the widget here. 460868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (system_bubble_.get() && 461868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) system_bubble_->bubble_view() && 462868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) system_bubble_->bubble_view()->GetWidget()) { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anchor = system_bubble_->bubble_view(); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anchor_type = TrayBubbleView::ANCHOR_TYPE_BUBBLE; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anchor = tray_container(); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) anchor_type = TrayBubbleView::ANCHOR_TYPE_TRAY; 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView::InitParams init_params(anchor_type, 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAnchorAlignment(), 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kTrayPopupMinWidth, 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kTrayPopupMaxWidth); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.arrow_color = kBackgroundColor; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.arrow_offset = GetTrayXOffset(notification_items_[0]); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_.reset( 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new internal::SystemBubbleWrapper(notification_bubble)); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_->InitView(this, anchor, &init_params); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (notification_bubble->bubble_view()->child_count() == 0) { 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is possible that none of the items generated actual notifications. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroyNotificationBubble(); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hide_notifications_) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble->SetVisible(false); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_area_widget()->SetHideWebNotifications(true); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::SetShelfAlignment(ShelfAlignment alignment) { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (alignment == shelf_alignment()) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internal::TrayBackgroundView::SetShelfAlignment(alignment); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateAfterShelfAlignmentChange(alignment); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy any existing bubble so that it is rebuilt correctly. 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_.reset(); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Rebuild any notification bubble. 498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (notification_bubble_) { 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_.reset(); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateNotificationBubble(); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::AnchorUpdated() { 505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (notification_bubble_) { 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_->bubble_view()->UpdateBubble(); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that the notification buble is above the launcher/status area. 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_bubble_->bubble_view()->GetWidget()->StackAtTop(); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateBubbleViewArrow(notification_bubble_->bubble_view()); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (system_bubble_) { 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble_view()->UpdateBubble(); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateBubbleViewArrow(system_bubble_->bubble_view()); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 SystemTray::GetAccessibleNameForTray() { 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) { 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroySystemBubble(); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateNotificationBubble(); // State changed, re-create notifications. 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetShelfLayoutManager()->UpdateAutoHideState(); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (notification_bubble_.get() && 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bubble_view == notification_bubble_->bubble_view()) { 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroyNotificationBubble(); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::ClickedOutsideBubble() { 533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!system_bubble_) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HideBubbleWithView(system_bubble_->bubble_view()); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::BubbleViewDestroyed() { 540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (system_bubble_) { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->DestroyItemViews(); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->BubbleViewDestroyed(); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::OnMouseEnteredView() { 547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (system_bubble_) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->StopAutoCloseTimer(); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::OnMouseExitedView() { 552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (system_bubble_) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->RestartAutoCloseTimer(); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 SystemTray::GetAccessibleNameForBubble() { 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetAccessibleNameForTray(); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect SystemTray::GetAnchorRect( 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* anchor_widget, 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView::AnchorType anchor_type, 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrayBubbleView::AnchorAlignment anchor_alignment) { 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetBubbleAnchorRect(anchor_widget, anchor_type, anchor_alignment); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideBubble(const TrayBubbleView* bubble_view) { 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HideBubbleWithView(bubble_view); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::PerformAction(const ui::Event& event) { 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're already showing the default view, hide it; otherwise, show it 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (and hide any popup that's currently shown). 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_bubble_->bubble()->Close(); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int arrow_offset = TrayBubbleView::InitParams::kArrowDefaultOffset; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_TAP) { 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::LocatedEvent& located_event = 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<const ui::LocatedEvent&>(event); 5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM || 5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shelf_alignment() == SHELF_ALIGNMENT_TOP) { 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point point(located_event.x(), 0); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPointToWidget(this, &point); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arrow_offset = point.x(); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset); 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ash 594