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/custom_button.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/cairo_cached_surface.h"
972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_chrome_button.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/gtk/gtk_theme_service.h"
1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/gtk_util.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/skbitmap_operations.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenCustomDrawButtonBase::CustomDrawButtonBase(GtkThemeService* theme_provider,
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                           int normal_id,
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                           int pressed_id,
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                           int hover_id,
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                           int disabled_id)
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : background_image_(NULL),
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      paint_override_(-1),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      normal_id_(normal_id),
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      pressed_id_(pressed_id),
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      hover_id_(hover_id),
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      disabled_id_(disabled_id),
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_(theme_provider),
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      flipped_(false) {
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < (GTK_STATE_INSENSITIVE + 1); ++i)
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    surfaces_[i].reset(new CairoCachedSurface);
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  background_image_.reset(new CairoCachedSurface);
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (theme_provider) {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Load images by pretending that we got a BROWSER_THEME_CHANGED
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // notification.
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    theme_provider->InitThemesFor(this);
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Add(this,
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   NotificationType::BROWSER_THEME_CHANGED,
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   NotificationService::AllSources());
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Load the button images from the resource bundle.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    surfaces_[GTK_STATE_NORMAL]->UsePixbuf(
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        normal_id_ ? rb.GetRTLEnabledPixbufNamed(normal_id_) : NULL);
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    surfaces_[GTK_STATE_ACTIVE]->UsePixbuf(
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        pressed_id_ ? rb.GetRTLEnabledPixbufNamed(pressed_id_) : NULL);
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    surfaces_[GTK_STATE_PRELIGHT]->UsePixbuf(
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        hover_id_ ? rb.GetRTLEnabledPixbufNamed(hover_id_) : NULL);
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    surfaces_[GTK_STATE_SELECTED]->UsePixbuf(NULL);
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    surfaces_[GTK_STATE_INSENSITIVE]->UsePixbuf(
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        disabled_id_ ? rb.GetRTLEnabledPixbufNamed(disabled_id_) : NULL);
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawButtonBase::~CustomDrawButtonBase() {
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint CustomDrawButtonBase::Width() const {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return surfaces_[0]->Width();
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint CustomDrawButtonBase::Height() const {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return surfaces_[0]->Height();
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean CustomDrawButtonBase::OnExpose(GtkWidget* widget,
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        GdkEventExpose* e,
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        gdouble hover_state) {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int paint_state = paint_override_ >= 0 ?
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    paint_override_ : GTK_WIDGET_STATE(widget);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the paint state is PRELIGHT then set it to NORMAL (we will paint the
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // hover state according to |hover_state_|).
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (paint_state == GTK_STATE_PRELIGHT)
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    paint_state = GTK_STATE_NORMAL;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool animating_hover = hover_state > 0.0 &&
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      paint_state == GTK_STATE_NORMAL;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CairoCachedSurface* pixbuf = PixbufForState(paint_state);
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CairoCachedSurface* hover_pixbuf = PixbufForState(GTK_STATE_PRELIGHT);
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!pixbuf || !pixbuf->valid())
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (animating_hover && (!hover_pixbuf || !hover_pixbuf->valid()))
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(widget->window));
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cairo_translate(cairo_context, widget->allocation.x, widget->allocation.y);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (flipped_) {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Horizontally flip the image for non-LTR/RTL reasons.
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cairo_translate(cairo_context, widget->allocation.width, 0.0f);
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cairo_scale(cairo_context, -1.0f, 1.0f);
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The widget might be larger than the pixbuf. Paint the pixbuf flush with the
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // start of the widget (left for LTR, right for RTL) and its bottom.
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect bounds = gfx::Rect(0, 0, pixbuf->Width(), 0);
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int x = gtk_util::MirroredLeftPointForRect(widget, bounds);
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int y = widget->allocation.height - pixbuf->Height();
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (background_image_->valid()) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    background_image_->SetSource(cairo_context, x, y);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cairo_paint(cairo_context);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pixbuf->SetSource(cairo_context, x, y);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cairo_paint(cairo_context);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (animating_hover) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hover_pixbuf->SetSource(cairo_context, x, y);
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cairo_paint_with_alpha(cairo_context, hover_state);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cairo_destroy(cairo_context);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget));
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (child)
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_container_propagate_expose(GTK_CONTAINER(widget), child, e);
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButtonBase::SetBackground(SkColor color,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         SkBitmap* image, SkBitmap* mask) {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!image || !mask) {
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (background_image_->valid()) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      background_image_->UsePixbuf(NULL);
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkBitmap img =
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SkBitmapOperations::CreateButtonBackground(color, *image, *mask);
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&img);
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    background_image_->UsePixbuf(pixbuf);
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    g_object_unref(pixbuf);
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButtonBase::Observe(NotificationType type,
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const NotificationSource& source, const NotificationDetails& details) {
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(theme_service_);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(NotificationType::BROWSER_THEME_CHANGED == type);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  surfaces_[GTK_STATE_NORMAL]->UsePixbuf(normal_id_ ?
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_->GetRTLEnabledPixbufNamed(normal_id_) : NULL);
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  surfaces_[GTK_STATE_ACTIVE]->UsePixbuf(pressed_id_ ?
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_->GetRTLEnabledPixbufNamed(pressed_id_) : NULL);
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  surfaces_[GTK_STATE_PRELIGHT]->UsePixbuf(hover_id_ ?
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_->GetRTLEnabledPixbufNamed(hover_id_) : NULL);
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  surfaces_[GTK_STATE_SELECTED]->UsePixbuf(NULL);
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  surfaces_[GTK_STATE_INSENSITIVE]->UsePixbuf(disabled_id_ ?
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_->GetRTLEnabledPixbufNamed(disabled_id_) : NULL);
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCairoCachedSurface* CustomDrawButtonBase::PixbufForState(int state) {
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CairoCachedSurface* pixbuf = surfaces_[state].get();
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Fall back to the default image if we don't have one for this state.
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!pixbuf || !pixbuf->valid())
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pixbuf = surfaces_[GTK_STATE_NORMAL].get();
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return pixbuf;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CustomDrawHoverController ---------------------------------------------------
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawHoverController::CustomDrawHoverController(GtkWidget* widget)
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : slide_animation_(this),
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      widget_(NULL) {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init(widget);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawHoverController::CustomDrawHoverController()
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : slide_animation_(this),
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      widget_(NULL) {
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawHoverController::~CustomDrawHoverController() {
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawHoverController::Init(GtkWidget* widget) {
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(widget_ == NULL);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  widget_ = widget;
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget_, "enter-notify-event",
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   G_CALLBACK(OnEnterThunk), this);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget_, "leave-notify-event",
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   G_CALLBACK(OnLeaveThunk), this);
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawHoverController::AnimationProgressed(
1953f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    const ui::Animation* animation) {
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_queue_draw(widget_);
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean CustomDrawHoverController::OnEnter(
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* widget,
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    GdkEventCrossing* event) {
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  slide_animation_.Show();
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean CustomDrawHoverController::OnLeave(
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* widget,
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    GdkEventCrossing* event) {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When the user is holding a mouse button, we don't want to animate.
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    slide_animation_.Reset();
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    slide_animation_.Hide();
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CustomDrawButton ------------------------------------------------------------
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickCustomDrawButton::CustomDrawButton(int normal_id,
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int pressed_id,
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int hover_id,
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int disabled_id)
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : button_base_(NULL, normal_id, pressed_id, hover_id, disabled_id),
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_(NULL) {
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Initialize the theme stuff with no theme_provider.
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetBrowserTheme();
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenCustomDrawButton::CustomDrawButton(GtkThemeService* theme_provider,
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int normal_id,
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int pressed_id,
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int hover_id,
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int disabled_id,
2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   const char* stock_id,
2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   GtkIconSize stock_size)
2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : button_base_(theme_provider, normal_id, pressed_id, hover_id,
2393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   disabled_id),
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_(theme_provider) {
2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  native_widget_.Own(gtk_image_new_from_stock(stock_id, stock_size));
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Init();
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  theme_service_->InitThemesFor(this);
2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this,
2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 NotificationType::BROWSER_THEME_CHANGED,
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 NotificationService::AllSources());
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenCustomDrawButton::CustomDrawButton(GtkThemeService* theme_provider,
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int normal_id,
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int pressed_id,
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int hover_id,
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   int disabled_id,
2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   GtkWidget* native_widget)
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : button_base_(theme_provider, normal_id, pressed_id, hover_id,
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   disabled_id),
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      native_widget_(native_widget),
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_(theme_provider) {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  theme_service_->InitThemesFor(this);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this,
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationType::BROWSER_THEME_CHANGED,
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawButton::~CustomDrawButton() {
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  widget_.Destroy();
2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  native_widget_.Destroy();
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButton::Init() {
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  widget_.Own(gtk_chrome_button_new());
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GTK_WIDGET_UNSET_FLAGS(widget(), GTK_CAN_FOCUS);
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget(), "expose-event",
2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   G_CALLBACK(OnCustomExposeThunk), this);
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hover_controller_.Init(widget());
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButton::Observe(NotificationType type,
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const NotificationSource& source, const NotificationDetails& details) {
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(NotificationType::BROWSER_THEME_CHANGED == type);
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetBrowserTheme();
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButton::SetPaintOverride(GtkStateType state) {
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_base_.set_paint_override(state);
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget()), state);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_queue_draw(widget());
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButton::UnsetPaintOverride() {
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_base_.set_paint_override(-1);
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(widget()));
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_queue_draw(widget());
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButton::SetBackground(SkColor color,
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     SkBitmap* image, SkBitmap* mask) {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_base_.SetBackground(color, image, mask);
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickgboolean CustomDrawButton::OnCustomExpose(GtkWidget* sender,
3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          GdkEventExpose* e) {
3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (UseGtkTheme()) {
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Continue processing this expose event.
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    double hover_state = hover_controller_.GetCurrentValue();
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return button_base_.OnExpose(sender, e, hover_state);
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawButton* CustomDrawButton::CloseButton(
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GtkThemeService* theme_provider) {
3193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CustomDrawButton* button = new CustomDrawButton(theme_provider, IDR_CLOSE_BAR,
3203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IDR_CLOSE_BAR_P, IDR_CLOSE_BAR_H, 0, GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return button;
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CustomDrawButton::SetBrowserTheme() {
3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (UseGtkTheme()) {
3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (native_widget_.get())
3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gtk_button_set_image(GTK_BUTTON(widget()), native_widget_.get());
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_set_size_request(widget(), -1, -1);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_set_app_paintable(widget(), FALSE);
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (native_widget_.get())
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gtk_button_set_image(GTK_BUTTON(widget()), NULL);
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_set_size_request(widget(), button_base_.Width(),
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                button_base_.Height());
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_set_app_paintable(widget(), TRUE);
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_chrome_button_set_use_gtk_rendering(
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      GTK_CHROME_BUTTON(widget()), UseGtkTheme());
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool CustomDrawButton::UseGtkTheme() {
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return theme_service_ && theme_service_->UseGtkTheme();
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
346