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();
}
|