15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/hover_controller_gtk.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 79ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_chrome_button.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_compat.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const gchar* kHoverControllerGtkKey = "__HOVER_CONTROLLER_GTK__"; 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HoverControllerGtk::HoverControllerGtk(GtkWidget* button) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : throb_animation_(this), 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hover_animation_(this), 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) button_(button) { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_ref(button_); 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0); 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signals_.Connect(button_, "enter-notify-event", 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnEnterThunk), this); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signals_.Connect(button_, "leave-notify-event", 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnLeaveThunk), this); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signals_.Connect(button_, "destroy", 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnDestroyThunk), this); 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signals_.Connect(button_, "hierarchy-changed", 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnHierarchyChangedThunk), this); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_object_get_data(G_OBJECT(button_), kHoverControllerGtkKey)) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NDEBUG 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_set_data(G_OBJECT(button), kHoverControllerGtkKey, this); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HoverControllerGtk::~HoverControllerGtk() { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HoverControllerGtk::StartThrobbing(int cycles) { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throb_animation_.StartThrobbing(cycles); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* HoverControllerGtk::CreateChromeButton() { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* widget = gtk_chrome_button_new(); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new HoverControllerGtk(widget); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return widget; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HoverControllerGtk* HoverControllerGtk::GetHoverControllerGtk( 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* button) { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<HoverControllerGtk*>( 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_get_data(G_OBJECT(button), kHoverControllerGtkKey)); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HoverControllerGtk::Destroy() { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), -1.0); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_set_data(G_OBJECT(button_), kHoverControllerGtkKey, NULL); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_unref(button_); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) button_ = NULL; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete this; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HoverControllerGtk::AnimationProgressed(const ui::Animation* animation) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!button_) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore the hover animation if we are throbbing. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (animation == &hover_animation_ && throb_animation_.is_animating()) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animation->GetCurrentValue()); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HoverControllerGtk::AnimationEnded(const ui::Animation* animation) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!button_) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (animation != &throb_animation_) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (throb_animation_.cycles_remaining() <= 1) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HoverControllerGtk::AnimationCanceled(const ui::Animation* animation) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimationEnded(animation); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean HoverControllerGtk::OnEnter(GtkWidget* widget, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventCrossing* event) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hover_animation_.Show(); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean HoverControllerGtk::OnLeave(GtkWidget* widget, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventCrossing* event) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the user is holding a mouse button, we don't want to animate. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hover_animation_.Reset(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hover_animation_.Hide(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HoverControllerGtk::OnHierarchyChanged(GtkWidget* widget, 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* previous_toplevel) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GTK+ does not emit leave-notify-event signals when a widget 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // becomes unanchored, so manually unset the hover states. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!gtk_widget_is_toplevel(gtk_widget_get_toplevel(widget))) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_state(button_, GTK_STATE_NORMAL); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hover_animation_.Reset(); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_chrome_button_set_hover_state(GTK_CHROME_BUTTON(button_), 0.0); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HoverControllerGtk::OnDestroy(GtkWidget* widget) { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Destroy(); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 128