// Copyright (c) 2010 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/chromeos/volume_bubble.h" #include #include "base/timer.h" #include "chrome/browser/chromeos/volume_bubble_view.h" #include "chrome/browser/views/info_bubble.h" #include "views/widget/root_view.h" namespace { const int kBubbleShowTimeoutSec = 2; const int kAnimationDurationMs = 200; // Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost. const double kVolumeBubbleXRatio = 0.18; // Vertical gap from the bottom of the screen in pixels. const int kVolumeBubbleBottomGap = 30; } // namespace namespace chromeos { // Temporary helper routine. Returns currently shown Chrome widget or NULL. // TODO(glotov): remove this in favor of enabling InfoBubble class act // without |parent| specified. crosbug.com/4025 static views::Widget* GetToplevelWidget() { views::Widget* widget = NULL; GList *window_list = gtk_window_list_toplevels(); for (GList* iter = window_list; iter; iter = g_list_next(iter)) { GtkWindow* const window = GTK_WINDOW(iter->data); if (window && GTK_WIDGET(window)->window == gdk_screen_get_active_window(gdk_screen_get_default())) { views::RootView* root = views::Widget::FindRootView(window); if (root) widget = root->GetWidget(); break; } } g_list_free(window_list); return widget; } VolumeBubble::VolumeBubble() : previous_percent_(-1), current_percent_(-1), bubble_(NULL), view_(NULL), animation_(this) { animation_.SetSlideDuration(kAnimationDurationMs); animation_.SetTweenType(Tween::LINEAR); } void VolumeBubble::ShowVolumeBubble(int percent) { if (percent < 0) percent = 0; if (percent > 100) percent = 100; if (previous_percent_ == -1) previous_percent_ = percent; current_percent_ = percent; if (!bubble_) { views::Widget* widget = GetToplevelWidget(); if (widget == NULL) return; DCHECK(view_ == NULL); view_ = new VolumeBubbleView; view_->Init(previous_percent_); // Calculate position of the volume bubble. // TODO(glotov): Place volume bubble over the keys initiated the // volume change. This metric must be specific to the given // architecture. crosbug.com/4028 gfx::Rect bounds; widget->GetBounds(&bounds, false); const gfx::Size view_size = view_->GetPreferredSize(); // Note that (x, y) is the point of the center of the bubble. const int x = view_size.width() / 2 + kVolumeBubbleXRatio * (bounds.width() - view_size.width()); const int y = bounds.height() - view_size.height() / 2 - kVolumeBubbleBottomGap; bubble_ = InfoBubble::ShowFocusless(widget, gfx::Rect(x, y, 0, 20), BubbleBorder::FLOAT, view_, this); } else { DCHECK(view_); timeout_timer_.Stop(); } if (animation_.is_animating()) animation_.End(); animation_.Reset(); animation_.Show(); timeout_timer_.Start(base::TimeDelta::FromSeconds(kBubbleShowTimeoutSec), this, &VolumeBubble::OnTimeout); } void VolumeBubble::OnTimeout() { if (bubble_) bubble_->Close(); } void VolumeBubble::InfoBubbleClosing(InfoBubble* info_bubble, bool) { DCHECK(info_bubble == bubble_); timeout_timer_.Stop(); animation_.Stop(); bubble_ = NULL; view_ = NULL; } void VolumeBubble::AnimationEnded(const Animation* animation) { previous_percent_ = current_percent_; } void VolumeBubble::AnimationProgressed(const Animation* animation) { if (view_) { view_->Update( Tween::ValueBetween(animation->GetCurrentValue(), previous_percent_, current_percent_)); } } } // namespace chromeos