OLD | NEW |
| (Empty) |
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 = >k_chrome_link_button_expose; | |
211 button_class->enter = >k_chrome_link_button_enter; | |
212 button_class->leave = >k_chrome_link_button_leave; | |
213 object_class->destroy = >k_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 | |
OLD | NEW |