Home | History | Annotate | Download | only in gtk
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/gtk/throbber_gtk.h"
      6 
      7 #include "base/logging.h"
      8 #include "chrome/browser/chrome_notification_types.h"
      9 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
     10 #include "content/public/browser/notification_source.h"
     11 #include "grit/ui_resources.h"
     12 #include "ui/base/animation/tween.h"
     13 #include "ui/gfx/image/cairo_cached_surface.h"
     14 
     15 namespace {
     16 
     17 // The length of a single cycle of the animation in milliseconds.
     18 const int kThrobberDurationMs = 750;
     19 
     20 }  // namespace
     21 
     22 ThrobberGtk::ThrobberGtk(GtkThemeService* theme_service)
     23     : theme_service_(theme_service),
     24       animation_(this),
     25       num_frames_(0) {
     26   DCHECK(theme_service_);
     27   Init();
     28 }
     29 
     30 ThrobberGtk::~ThrobberGtk() {
     31   widget_.Destroy();
     32 }
     33 
     34 void ThrobberGtk::Start() {
     35   animation_.Show();
     36 }
     37 
     38 void ThrobberGtk::Stop() {
     39   animation_.Reset();
     40 }
     41 
     42 void ThrobberGtk::AnimationEnded(const ui::Animation* animation) {
     43   animation_.Reset();
     44   animation_.Show();
     45 }
     46 
     47 void ThrobberGtk::AnimationProgressed(const ui::Animation* animation) {
     48   gtk_widget_queue_draw(widget_.get());
     49 }
     50 
     51 void ThrobberGtk::Observe(int type,
     52                           const content::NotificationSource& source,
     53                           const content::NotificationDetails& details) {
     54   DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
     55   LoadFrames();
     56   gtk_widget_queue_draw(widget_.get());
     57 }
     58 
     59 gboolean ThrobberGtk::OnExpose(GtkWidget* widget, GdkEventExpose* expose) {
     60   cairo_t* cairo_context =
     61       gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget)));
     62   GtkAllocation allocation;
     63   gtk_widget_get_allocation(widget, &allocation);
     64   cairo_translate(cairo_context, allocation.x, allocation.y);
     65 
     66   gfx::CairoCachedSurface* cairo_frames = frames_.ToCairo();
     67   const int frame =
     68       static_cast<int>(animation_.GetCurrentValue() * (num_frames_ - 1));
     69   const int image_size = cairo_frames->Height();
     70   const int image_offset = frame * image_size;
     71 
     72   cairo_frames->SetSource(cairo_context, widget, -image_offset, 0);
     73   cairo_rectangle(cairo_context, 0, 0, image_size, image_size);
     74   cairo_fill(cairo_context);
     75   cairo_destroy(cairo_context);
     76 
     77   return TRUE;
     78 }
     79 
     80 void ThrobberGtk::Init() {
     81   animation_.SetSlideDuration(kThrobberDurationMs);
     82   animation_.SetTweenType(ui::Tween::LINEAR);
     83   widget_.Own(gtk_image_new());
     84   gtk_widget_set_can_focus(widget_.get(), FALSE);
     85   g_signal_connect(widget_.get(), "expose-event", G_CALLBACK(OnExposeThunk),
     86                    this);
     87 
     88   theme_service_->InitThemesFor(this);
     89   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
     90                  content::Source<ThemeService>(theme_service_));
     91 }
     92 
     93 void ThrobberGtk::LoadFrames() {
     94   frames_ = theme_service_->GetImageNamed(IDR_THROBBER);
     95   DCHECK(!frames_.IsEmpty());
     96   const int width = frames_.ToCairo()->Width();
     97   const int height = frames_.ToCairo()->Height();
     98   DCHECK_EQ(0, width % height);
     99   num_frames_ = width / height;
    100 
    101   gtk_widget_set_size_request(widget_.get(), height, height);
    102 }
    103