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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/setting_level_bubble.h" 6 7 #include <gdk/gdk.h> 8 9 #include "base/timer.h" 10 #include "chrome/browser/chromeos/login/background_view.h" 11 #include "chrome/browser/chromeos/login/login_utils.h" 12 #include "chrome/browser/chromeos/setting_level_bubble_view.h" 13 #include "chrome/browser/profiles/profile_manager.h" 14 #include "chrome/browser/ui/browser.h" 15 #include "chrome/browser/ui/browser_list.h" 16 #include "chrome/browser/ui/browser_window.h" 17 #include "chrome/browser/ui/views/bubble/bubble.h" 18 #include "views/widget/root_view.h" 19 20 namespace { 21 22 const int kBubbleShowTimeoutSec = 2; 23 const int kAnimationDurationMs = 200; 24 25 // Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost. 26 const double kBubbleXRatio = 0.5; 27 28 // Vertical gap from the bottom of the screen in pixels. 29 const int kBubbleBottomGap = 30; 30 31 int LimitPercent(int percent) { 32 if (percent < 0) 33 percent = 0; 34 else if (percent > 100) 35 percent = 100; 36 return percent; 37 } 38 39 } // namespace 40 41 namespace chromeos { 42 43 // Temporary helper routine. Tries to first return the widget from the 44 // most-recently-focused normal browser window, then from a login 45 // background, and finally NULL if both of those fail. 46 // TODO(glotov): remove this in favor of enabling Bubble class act 47 // without |parent| specified. crosbug.com/4025 48 static views::Widget* GetToplevelWidget() { 49 GtkWindow* window = NULL; 50 51 // We just use the default profile here -- this gets overridden as needed 52 // in Chrome OS depending on whether the user is logged in or not. 53 Browser* browser = 54 BrowserList::FindBrowserWithType( 55 ProfileManager::GetDefaultProfile(), 56 Browser::TYPE_NORMAL, 57 true); // match_incognito 58 if (browser) { 59 window = GTK_WINDOW(browser->window()->GetNativeHandle()); 60 } else { 61 // Otherwise, see if there's a background window that we can use. 62 BackgroundView* background = LoginUtils::Get()->GetBackgroundView(); 63 if (background) 64 window = GTK_WINDOW(background->GetNativeWindow()); 65 } 66 67 if (!window) 68 return NULL; 69 70 views::NativeWidget* native_widget = 71 views::NativeWidget::GetNativeWidgetForNativeWindow(window); 72 return native_widget->GetWidget(); 73 } 74 75 SettingLevelBubble::SettingLevelBubble(SkBitmap* increase_icon, 76 SkBitmap* decrease_icon, 77 SkBitmap* zero_icon) 78 : previous_percent_(-1), 79 current_percent_(-1), 80 increase_icon_(increase_icon), 81 decrease_icon_(decrease_icon), 82 zero_icon_(zero_icon), 83 bubble_(NULL), 84 view_(NULL), 85 animation_(this) { 86 animation_.SetSlideDuration(kAnimationDurationMs); 87 animation_.SetTweenType(ui::Tween::LINEAR); 88 } 89 90 void SettingLevelBubble::ShowBubble(int percent) { 91 percent = LimitPercent(percent); 92 if (previous_percent_ == -1) 93 previous_percent_ = percent; 94 current_percent_ = percent; 95 96 SkBitmap* icon = increase_icon_; 97 if (current_percent_ == 0) 98 icon = zero_icon_; 99 else if (current_percent_ < previous_percent_) 100 icon = decrease_icon_; 101 102 if (!bubble_) { 103 views::Widget* widget = GetToplevelWidget(); 104 if (widget == NULL) 105 return; 106 DCHECK(view_ == NULL); 107 view_ = new SettingLevelBubbleView; 108 view_->Init(icon, previous_percent_); 109 // Calculate position of the bubble. 110 gfx::Rect bounds = widget->GetClientAreaScreenBounds(); 111 const gfx::Size view_size = view_->GetPreferredSize(); 112 // Note that (x, y) is the point of the center of the bubble. 113 const int x = view_size.width() / 2 + 114 kBubbleXRatio * (bounds.width() - view_size.width()); 115 const int y = bounds.height() - view_size.height() / 2 - kBubbleBottomGap; 116 bubble_ = Bubble::ShowFocusless(widget, // parent 117 gfx::Rect(x, y, 0, 20), 118 BubbleBorder::FLOAT, 119 view_, // contents 120 this, // delegate 121 true); // show while screen is locked 122 } else { 123 DCHECK(view_); 124 timeout_timer_.Stop(); 125 view_->SetIcon(icon); 126 } 127 if (animation_.is_animating()) 128 animation_.End(); 129 animation_.Reset(); 130 animation_.Show(); 131 timeout_timer_.Start(base::TimeDelta::FromSeconds(kBubbleShowTimeoutSec), 132 this, &SettingLevelBubble::OnTimeout); 133 } 134 135 void SettingLevelBubble::HideBubble() { 136 if (bubble_) 137 bubble_->Close(); 138 } 139 140 void SettingLevelBubble::UpdateWithoutShowingBubble(int percent) { 141 percent = LimitPercent(percent); 142 143 previous_percent_ = 144 animation_.is_animating() ? 145 animation_.GetCurrentValue() : 146 current_percent_; 147 if (previous_percent_ < 0) 148 previous_percent_ = percent; 149 current_percent_ = percent; 150 151 if (animation_.is_animating()) 152 animation_.End(); 153 animation_.Reset(); 154 animation_.Show(); 155 } 156 157 void SettingLevelBubble::OnTimeout() { 158 HideBubble(); 159 } 160 161 void SettingLevelBubble::BubbleClosing(Bubble* bubble, bool) { 162 DCHECK(bubble == bubble_); 163 timeout_timer_.Stop(); 164 animation_.Stop(); 165 bubble_ = NULL; 166 view_ = NULL; 167 } 168 169 void SettingLevelBubble::AnimationEnded(const ui::Animation* animation) { 170 previous_percent_ = current_percent_; 171 } 172 173 void SettingLevelBubble::AnimationProgressed(const ui::Animation* animation) { 174 if (view_) { 175 view_->Update( 176 ui::Tween::ValueBetween(animation->GetCurrentValue(), 177 previous_percent_, 178 current_percent_)); 179 } 180 } 181 182 } // namespace chromeos 183