summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/throb_controller_gtk.cc
blob: 422d388b1f299d1f12ebd7043fcf34b6763eb29b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// 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/gtk/throb_controller_gtk.h"

#include "base/message_loop.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"

static const gchar* kThrobControllerGtkKey = "__THROB_CONTROLLER_GTK__";

ThrobControllerGtk::ThrobControllerGtk(GtkWidget* button)
    : animation_(this),
      button_(button) {
  g_object_ref(button_);
  g_signal_connect(button_, "destroy", G_CALLBACK(OnButtonDestroy), this);

#ifndef NDEBUG
  if (g_object_get_data(G_OBJECT(button_), kThrobControllerGtkKey))
    NOTREACHED();
#endif  // !NDEBUG

  g_object_set_data(G_OBJECT(button), kThrobControllerGtkKey, this);
}

ThrobControllerGtk::~ThrobControllerGtk() {
}

void ThrobControllerGtk::StartThrobbing(int cycles) {
  animation_.StartThrobbing(cycles);
}

// static
ThrobControllerGtk* ThrobControllerGtk::GetThrobControllerGtk(
    GtkWidget* button) {
  return reinterpret_cast<ThrobControllerGtk*>(
      g_object_get_data(G_OBJECT(button), kThrobControllerGtkKey));
}

// static
void ThrobControllerGtk::ThrobFor(GtkWidget* button) {
  if (!GTK_IS_CHROME_BUTTON(button)) {
    NOTREACHED();
    return;
  }

  (new ThrobControllerGtk(button))->
      StartThrobbing(std::numeric_limits<int>::max());
}

void ThrobControllerGtk::Destroy() {
  gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), -1.0);
  g_signal_handlers_disconnect_by_func(
      button_,
      reinterpret_cast<gpointer>(OnButtonDestroy),
      this);
  g_object_set_data(G_OBJECT(button_), kThrobControllerGtkKey, NULL);
  g_object_unref(button_);
  button_ = NULL;

  // Since this can be called from within AnimationEnded(), which is called
  // while ThrobAnimation is still doing work, we need to let the stack unwind
  // before |animation_| gets deleted.
  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}

void ThrobControllerGtk::AnimationProgressed(const Animation* animation) {
  if (!button_)
    return;

  gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_),
                                    animation->GetCurrentValue());
}

void ThrobControllerGtk::AnimationEnded(const Animation* animation) {
  if (!button_)
    return;

  if (animation_.cycles_remaining() <= 1)
    Destroy();
}

void ThrobControllerGtk::AnimationCanceled(const Animation* animation) {
  if (!button_)
    return;

  if (animation_.cycles_remaining() <= 1)
    Destroy();
}

// static
void ThrobControllerGtk::OnButtonDestroy(GtkWidget* widget,
                                         ThrobControllerGtk* button) {
  button->Destroy();
}