Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / gtk_chrome_link_button.cc
1 // Copyright (c) 2012 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/gtk_chrome_link_button.h"
6
7 #include <stdlib.h>
8
9 #include "chrome/browser/ui/gtk/gtk_util.h"
10 #include "ui/gfx/gtk_compat.h"
11 #include "ui/gfx/gtk_util.h"
12
13 static const gchar* kLinkMarkup = "<u><span color=\"%s\">%s</span></u>";
14 static const gchar* kInsensitiveLinkMarkup = "<span color=\"%s\">%s</span>";
15
16 namespace {
17
18 // Set the GTK style on our custom link button. We don't want any border around
19 // the link text.
20 void SetLinkButtonStyle() {
21   static bool style_was_set = false;
22
23   if (style_was_set)
24     return;
25   style_was_set = true;
26
27   gtk_rc_parse_string(
28       "style \"chrome-link-button\" {"
29       "  GtkButton::inner-border = {0, 0, 0, 0}"
30       "  GtkButton::child-displacement-x = 0"
31       "  GtkButton::child-displacement-y = 0"
32       "  xthickness = 0"
33       "  ythickness = 0"
34       "}"
35       "widget_class \"*.<GtkChromeLinkButton>\" style \"chrome-link-button\"");
36 }
37
38 static void gtk_chrome_link_button_destroy_text_resources(
39     GtkChromeLinkButton* button) {
40   g_free(button->native_markup);
41   button->native_markup = NULL;
42   g_free(button->normal_markup);
43   button->normal_markup = NULL;
44   g_free(button->pressed_markup);
45   button->pressed_markup = NULL;
46   g_free(button->insensitive_markup);
47   button->insensitive_markup = NULL;
48
49   g_free(button->text);
50   button->text = NULL;
51 }
52
53 }  // namespace
54
55 G_BEGIN_DECLS
56 G_DEFINE_TYPE(GtkChromeLinkButton, gtk_chrome_link_button, GTK_TYPE_BUTTON)
57
58 static void gtk_chrome_link_button_set_text(GtkChromeLinkButton* button) {
59   // If we were called before we were realized, abort. We'll be called for
60   // real when |button| is realized.
61   if (!gtk_widget_get_realized(GTK_WIDGET(button)))
62     return;
63
64   g_free(button->native_markup);
65   button->native_markup = NULL;
66   g_free(button->normal_markup);
67   button->normal_markup = NULL;
68   g_free(button->pressed_markup);
69   button->pressed_markup = NULL;
70   g_free(button->insensitive_markup);
71   button->insensitive_markup = NULL;
72
73   gchar* text = button->text;
74   gboolean uses_markup = button->uses_markup;
75
76   GtkStyle* style = gtk_rc_get_style(button->label);
77   GdkColor insensitive_color = style->fg[GTK_STATE_INSENSITIVE];
78   gchar insensitive_color_spec[9];
79   snprintf(insensitive_color_spec, 9, "#%02X%02X%02X",
80            insensitive_color.red / 257, insensitive_color.green / 257,
81            insensitive_color.blue / 257);
82
83   if (!uses_markup) {
84     button->normal_markup = g_markup_printf_escaped(kLinkMarkup,
85                                                     button->normal_color,
86                                                     text);
87     button->pressed_markup = g_markup_printf_escaped(kLinkMarkup, "red", text);
88     button->insensitive_markup = g_markup_printf_escaped(kInsensitiveLinkMarkup,
89                                                          insensitive_color_spec,
90                                                          text);
91   } else {
92     button->normal_markup = g_strdup_printf(kLinkMarkup, button->normal_color,
93                                             text);
94
95     button->pressed_markup = g_strdup_printf(kLinkMarkup, "red", text);
96     button->insensitive_markup = g_strdup_printf(kInsensitiveLinkMarkup,
97                                                  insensitive_color_spec,
98                                                  text);
99   }
100
101   // Get the current GTK theme's link button text color.
102   GdkColor* native_color = NULL;
103   gtk_widget_style_get(GTK_WIDGET(button), "link-color", &native_color, NULL);
104
105   if (native_color) {
106     gchar color_spec[9];
107     snprintf(color_spec, 9, "#%02X%02X%02X", native_color->red / 257,
108              native_color->green / 257, native_color->blue / 257);
109     gdk_color_free(native_color);
110
111     if (!uses_markup) {
112       button->native_markup = g_markup_printf_escaped(kLinkMarkup,
113           color_spec, text);
114     } else {
115       button->native_markup = g_strdup_printf(kLinkMarkup, color_spec, text);
116     }
117   } else {
118     // If the theme doesn't have a link color, just use blue. This matches the
119     // default for GtkLinkButton.
120     button->native_markup = g_strdup(button->normal_markup);
121   }
122
123   gtk_label_set_markup(GTK_LABEL(button->label),
124       button->using_native_theme ? button->native_markup :
125       button->normal_markup);
126 }
127
128 static void gtk_chrome_link_button_style_changed(GtkChromeLinkButton* button) {
129   // Regenerate the link with the possibly new colors after the user has
130   // changed his GTK style.
131   gtk_chrome_link_button_set_text(button);
132
133   if (gtk_widget_get_visible(GTK_WIDGET(button)))
134     gtk_widget_queue_draw(GTK_WIDGET(button));
135 }
136
137 static gboolean gtk_chrome_link_button_expose(GtkWidget* widget,
138                                               GdkEventExpose* event) {
139   GtkChromeLinkButton* button = GTK_CHROME_LINK_BUTTON(widget);
140   GtkWidget* label = button->label;
141   GtkStateType widget_state = gtk_widget_get_state(widget);
142
143   if (widget_state != button->label_state) {
144     switch (widget_state) {
145       case GTK_STATE_NORMAL:
146         gtk_label_set_markup(GTK_LABEL(label),
147             button->using_native_theme ? button->native_markup :
148                                          button->normal_markup);
149         break;
150       case GTK_STATE_ACTIVE:
151         gtk_label_set_markup(GTK_LABEL(label), button->pressed_markup);
152         break;
153       case GTK_STATE_INSENSITIVE:
154         gtk_label_set_markup(GTK_LABEL(label), button->insensitive_markup);
155         break;
156       default:
157         break;
158     }
159     button->label_state = widget_state;
160   }
161
162   // Draw the link inside the button.
163   gtk_container_propagate_expose(GTK_CONTAINER(widget), label, event);
164
165   // Draw the focus rectangle.
166   if (gtk_widget_has_focus(widget)) {
167     GtkAllocation allocation;
168     gtk_widget_get_allocation(widget, &allocation);
169     gtk_paint_focus(gtk_widget_get_style(widget),
170                     gtk_widget_get_window(widget),
171                     gtk_widget_get_state(widget),
172                     &event->area, widget, NULL,
173                     allocation.x, allocation.y,
174                     allocation.width, allocation.height);
175   }
176
177   return TRUE;
178 }
179
180 static void gtk_chrome_link_button_enter(GtkButton* button) {
181   GtkWidget* widget = GTK_WIDGET(button);
182   GtkChromeLinkButton* link_button = GTK_CHROME_LINK_BUTTON(button);
183   gdk_window_set_cursor(gtk_widget_get_window(widget),
184                         link_button->hand_cursor);
185 }
186
187 static void gtk_chrome_link_button_leave(GtkButton* button) {
188   GtkWidget* widget = GTK_WIDGET(button);
189   gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
190 }
191
192 static void gtk_chrome_link_button_destroy(GtkObject* object) {
193   GtkChromeLinkButton* button = GTK_CHROME_LINK_BUTTON(object);
194
195   gtk_chrome_link_button_destroy_text_resources(button);
196
197   button->hand_cursor = NULL;
198
199   GTK_OBJECT_CLASS(gtk_chrome_link_button_parent_class)->destroy(object);
200 }
201
202 static void gtk_chrome_link_button_class_init(
203     GtkChromeLinkButtonClass* link_button_class) {
204   GtkWidgetClass* widget_class =
205       reinterpret_cast<GtkWidgetClass*>(link_button_class);
206   GtkButtonClass* button_class =
207       reinterpret_cast<GtkButtonClass*>(link_button_class);
208   GtkObjectClass* object_class =
209       reinterpret_cast<GtkObjectClass*>(link_button_class);
210   widget_class->expose_event = &gtk_chrome_link_button_expose;
211   button_class->enter = &gtk_chrome_link_button_enter;
212   button_class->leave = &gtk_chrome_link_button_leave;
213   object_class->destroy = &gtk_chrome_link_button_destroy;
214 }
215
216 static void gtk_chrome_link_button_init(GtkChromeLinkButton* button) {
217   SetLinkButtonStyle();
218
219   // We put a label in a button so we can connect to the click event. We don't
220   // let the button draw itself; catch all expose events to the button and pass
221   // them through to the label.
222   button->label = gtk_label_new(NULL);
223   button->normal_markup = NULL;
224   button->pressed_markup = NULL;
225   button->label_state = GTK_STATE_NORMAL;
226   strncpy(button->normal_color, "blue", 9);
227   button->native_markup = NULL;
228   button->using_native_theme = TRUE;
229   button->hand_cursor = gfx::GetCursor(GDK_HAND2);
230   button->text = NULL;
231
232   gtk_container_add(GTK_CONTAINER(button), button->label);
233   gtk_widget_set_app_paintable(GTK_WIDGET(button), TRUE);
234   g_signal_connect(button, "realize",
235                    G_CALLBACK(gtk_chrome_link_button_set_text), NULL);
236   g_signal_connect(button, "style-set",
237                    G_CALLBACK(gtk_chrome_link_button_style_changed), NULL);
238 }
239
240 GtkWidget* gtk_chrome_link_button_new(const char* text) {
241   GtkWidget* lb = GTK_WIDGET(g_object_new(GTK_TYPE_CHROME_LINK_BUTTON, NULL));
242   GTK_CHROME_LINK_BUTTON(lb)->text = g_strdup(text);
243   GTK_CHROME_LINK_BUTTON(lb)->uses_markup = FALSE;
244
245   return lb;
246 }
247
248 GtkWidget* gtk_chrome_link_button_new_with_markup(const char* markup) {
249   GtkWidget* lb = GTK_WIDGET(g_object_new(GTK_TYPE_CHROME_LINK_BUTTON, NULL));
250   GTK_CHROME_LINK_BUTTON(lb)->text = g_strdup(markup);
251   GTK_CHROME_LINK_BUTTON(lb)->uses_markup = TRUE;
252
253   return lb;
254 }
255
256 void gtk_chrome_link_button_set_use_gtk_theme(GtkChromeLinkButton* button,
257                                               gboolean use_gtk) {
258   if (use_gtk != button->using_native_theme) {
259     button->using_native_theme = use_gtk;
260
261     gtk_chrome_link_button_set_text(button);
262
263     if (gtk_widget_get_visible(GTK_WIDGET(button)))
264       gtk_widget_queue_draw(GTK_WIDGET(button));
265   }
266 }
267
268 void gtk_chrome_link_button_set_label(GtkChromeLinkButton* button,
269                                       const char* text) {
270   g_free(button->text);
271   button->text = g_strdup(text);
272
273   gtk_chrome_link_button_set_text(button);
274
275   if (gtk_widget_get_visible(GTK_WIDGET(button)))
276     gtk_widget_queue_draw(GTK_WIDGET(button));
277 }
278
279 void gtk_chrome_link_button_set_normal_color(GtkChromeLinkButton* button,
280                                              const GdkColor* color) {
281   if (color) {
282     snprintf(button->normal_color, 9, "#%02X%02X%02X", color->red / 257,
283              color->green / 257, color->blue / 257);
284   } else {
285     strncpy(button->normal_color, "blue", 9);
286   }
287
288   gtk_chrome_link_button_set_text(button);
289
290   if (gtk_widget_get_visible(GTK_WIDGET(button)))
291     gtk_widget_queue_draw(GTK_WIDGET(button));
292 }
293
294 G_END_DECLS