Home | History | Annotate | Download | only in gtk
      1 // Copyright (c) 2011 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/hover_controller_gtk.h"
      6 
      7 #include "base/message_loop/message_loop.h"
      8 #include "chrome/browser/ui/gtk/gtk_chrome_button.h"
      9 #include "ui/base/gtk/gtk_compat.h"
     10 
     11 static const gchar* kHoverControllerGtkKey = "__HOVER_CONTROLLER_GTK__";
     12 
     13 HoverControllerGtk::HoverControllerGtk(GtkWidget* button)
     14     : throb_animation_(this),
     15       hover_animation_(this),
     16       button_(button) {
     17   g_object_ref(button_);
     18   gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0);
     19 
     20   signals_.Connect(button_, "enter-notify-event",
     21                    G_CALLBACK(OnEnterThunk), this);
     22   signals_.Connect(button_, "leave-notify-event",
     23                    G_CALLBACK(OnLeaveThunk), this);
     24   signals_.Connect(button_, "destroy",
     25                    G_CALLBACK(OnDestroyThunk), this);
     26   signals_.Connect(button_, "hierarchy-changed",
     27                    G_CALLBACK(OnHierarchyChangedThunk), this);
     28 
     29 #ifndef NDEBUG
     30   if (g_object_get_data(G_OBJECT(button_), kHoverControllerGtkKey))
     31     NOTREACHED();
     32 #endif  // !NDEBUG
     33 
     34   g_object_set_data(G_OBJECT(button), kHoverControllerGtkKey, this);
     35 }
     36 
     37 HoverControllerGtk::~HoverControllerGtk() {
     38 }
     39 
     40 void HoverControllerGtk::StartThrobbing(int cycles) {
     41   throb_animation_.StartThrobbing(cycles);
     42 }
     43 
     44 // static
     45 GtkWidget* HoverControllerGtk::CreateChromeButton() {
     46   GtkWidget* widget = gtk_chrome_button_new();
     47   new HoverControllerGtk(widget);
     48   return widget;
     49 }
     50 
     51 // static
     52 HoverControllerGtk* HoverControllerGtk::GetHoverControllerGtk(
     53     GtkWidget* button) {
     54   return reinterpret_cast<HoverControllerGtk*>(
     55       g_object_get_data(G_OBJECT(button), kHoverControllerGtkKey));
     56 }
     57 
     58 void HoverControllerGtk::Destroy() {
     59   gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), -1.0);
     60 
     61   g_object_set_data(G_OBJECT(button_), kHoverControllerGtkKey, NULL);
     62   g_object_unref(button_);
     63   button_ = NULL;
     64 
     65   delete this;
     66 }
     67 
     68 void HoverControllerGtk::AnimationProgressed(const ui::Animation* animation) {
     69   if (!button_)
     70     return;
     71 
     72   // Ignore the hover animation if we are throbbing.
     73   if (animation == &hover_animation_ && throb_animation_.is_animating())
     74     return;
     75 
     76   gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_),
     77                                     animation->GetCurrentValue());
     78 }
     79 
     80 void HoverControllerGtk::AnimationEnded(const ui::Animation* animation) {
     81   if (!button_)
     82     return;
     83   if (animation != &throb_animation_)
     84     return;
     85 
     86   if (throb_animation_.cycles_remaining() <= 1)
     87     gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0);
     88 }
     89 
     90 void HoverControllerGtk::AnimationCanceled(const ui::Animation* animation) {
     91   AnimationEnded(animation);
     92 }
     93 
     94 gboolean HoverControllerGtk::OnEnter(GtkWidget* widget,
     95                                      GdkEventCrossing* event) {
     96   hover_animation_.Show();
     97 
     98   return FALSE;
     99 }
    100 
    101 gboolean HoverControllerGtk::OnLeave(GtkWidget* widget,
    102                                      GdkEventCrossing* event) {
    103   // When the user is holding a mouse button, we don't want to animate.
    104   if (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) {
    105     hover_animation_.Reset();
    106     gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0);
    107   } else {
    108     hover_animation_.Hide();
    109   }
    110 
    111   return FALSE;
    112 }
    113 
    114 void HoverControllerGtk::OnHierarchyChanged(GtkWidget* widget,
    115                                             GtkWidget* previous_toplevel) {
    116   // GTK+ does not emit leave-notify-event signals when a widget
    117   // becomes unanchored, so manually unset the hover states.
    118   if (!gtk_widget_is_toplevel(gtk_widget_get_toplevel(widget))) {
    119     gtk_widget_set_state(button_, GTK_STATE_NORMAL);
    120     hover_animation_.Reset();
    121     gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0.0);
    122   }
    123 }
    124 
    125 void HoverControllerGtk::OnDestroy(GtkWidget* widget) {
    126   Destroy();
    127 }
    128