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