172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/hover_controller_gtk.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_chrome_button.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const gchar* kHoverControllerGtkKey = "__HOVER_CONTROLLER_GTK__";
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHoverControllerGtk::HoverControllerGtk(GtkWidget* button)
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : throb_animation_(this),
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      hover_animation_(this),
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      button_(button) {
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_object_ref(button_);
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0);
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(button_, "enter-notify-event",
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnEnterThunk), this);
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(button_, "leave-notify-event",
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnLeaveThunk), this);
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(button_, "destroy",
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnDestroyThunk), this);
25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  signals_.Connect(button_, "hierarchy-changed",
26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                   G_CALLBACK(OnHierarchyChangedThunk), this);
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifndef NDEBUG
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (g_object_get_data(G_OBJECT(button_), kHoverControllerGtkKey))
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // !NDEBUG
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_object_set_data(G_OBJECT(button), kHoverControllerGtkKey, this);
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHoverControllerGtk::~HoverControllerGtk() {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HoverControllerGtk::StartThrobbing(int cycles) {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  throb_animation_.StartThrobbing(cycles);
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGtkWidget* HoverControllerGtk::CreateChromeButton() {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* widget = gtk_chrome_button_new();
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new HoverControllerGtk(widget);
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return widget;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHoverControllerGtk* HoverControllerGtk::GetHoverControllerGtk(
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* button) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return reinterpret_cast<HoverControllerGtk*>(
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      g_object_get_data(G_OBJECT(button), kHoverControllerGtkKey));
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HoverControllerGtk::Destroy() {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), -1.0);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_object_set_data(G_OBJECT(button_), kHoverControllerGtkKey, NULL);
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_object_unref(button_);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_ = NULL;
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete this;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid HoverControllerGtk::AnimationProgressed(const ui::Animation* animation) {
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!button_)
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ignore the hover animation if we are throbbing.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (animation == &hover_animation_ && throb_animation_.is_animating())
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_),
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    animation->GetCurrentValue());
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid HoverControllerGtk::AnimationEnded(const ui::Animation* animation) {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!button_)
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (animation != &throb_animation_)
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (throb_animation_.cycles_remaining() <= 1)
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0);
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid HoverControllerGtk::AnimationCanceled(const ui::Animation* animation) {
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AnimationEnded(animation);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean HoverControllerGtk::OnEnter(GtkWidget* widget,
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     GdkEventCrossing* event) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hover_animation_.Show();
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean HoverControllerGtk::OnLeave(GtkWidget* widget,
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     GdkEventCrossing* event) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When the user is holding a mouse button, we don't want to animate.
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hover_animation_.Reset();
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hover_animation_.Hide();
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid HoverControllerGtk::OnHierarchyChanged(GtkWidget* widget,
114731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            GtkWidget* previous_toplevel) {
115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // GTK+ does not emit leave-notify-event signals when a widget
116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // becomes unanchored, so manually unset the hover states.
117731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(widget))) {
118731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    gtk_widget_set_state(button_, GTK_STATE_NORMAL);
119731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    hover_animation_.Reset();
120731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0.0);
121731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
122731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HoverControllerGtk::OnDestroy(GtkWidget* widget) {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Destroy();
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
127