2008-07-04 Emmanuele Bassi <ebassi@openedhand.com>
[clutter-gtk] / clutter-gtk / gtk-clutter-util.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <gdk-pixbuf/gdk-pixbuf.h>
6 #include <gtk/gtk.h>
7 #include <clutter/clutter.h>
8
9 #include "gtk-clutter-util.h"
10
11 /**
12  * SECTION:gtk-clutter-util
13  * @short_description: Utility functions for integrating Clutter in GTK+
14  *
15  * In order to properly integrate a Clutter scene into a GTK+ applications
16  * a certain degree of state must be retrieved from GTK+ itself.
17  *
18  * Clutter-GTK provides API for easing the process of synchronizing colors
19  * with the current GTK+ theme and for loading image sources from #GdkPixbuf,
20  * GTK+ stock items and icon themes.
21  */
22
23 static inline void
24 gtk_clutter_get_component (GtkWidget    *widget,
25                            GtkRcFlags    component,
26                            GtkStateType  state,
27                            ClutterColor *color)
28 {
29   GtkStyle *style = gtk_widget_get_style (widget);
30   GdkColor gtk_color = { 0, };
31
32   switch (component)
33     {
34     case GTK_RC_FG:
35       gtk_color = style->fg[state];
36       break;
37
38     case GTK_RC_BG:
39       gtk_color = style->bg[state];
40       break;
41
42     case GTK_RC_TEXT:
43       gtk_color = style->text[state];
44       break;
45
46     case GTK_RC_BASE:
47       gtk_color = style->base[state];
48       break;
49
50     default:
51       g_assert_not_reached ();
52       break;
53     }
54
55   color->red   = CLAMP (((gtk_color.red   / 65535.0) * 255), 0, 255);
56   color->green = CLAMP (((gtk_color.green / 65535.0) * 255), 0, 255);
57   color->blue  = CLAMP (((gtk_color.blue  / 65535.0) * 255), 0, 255);
58   color->alpha = 255;
59 }
60
61 /**
62  * gtk_clutter_get_fg_color:
63  * @widget: a #GtkWidget
64  * @state: a state
65  * @color: return location for a #ClutterColor
66  *
67  * Retrieves the foreground color of @widget for the given @state and copies
68  * it into @color.
69  *
70  * Since: 0.8
71  */
72 void
73 gtk_clutter_get_fg_color (GtkWidget    *widget,
74                           GtkStateType  state,
75                           ClutterColor *color)
76 {
77   g_return_if_fail (GTK_IS_WIDGET (widget));
78   g_return_if_fail (state >= GTK_STATE_NORMAL &&
79                     state <= GTK_STATE_INSENSITIVE);
80   g_return_if_fail (color != NULL);
81
82   gtk_clutter_get_component (widget, GTK_RC_FG, state, color);
83 }
84
85 /**
86  * gtk_clutter_get_bg_color:
87  * @widget: a #GtkWidget
88  * @state: a state
89  * @color: return location for a #ClutterColor
90  *
91  * Retrieves the background color of @widget for the given @state and copies
92  * it into @color.
93  *
94  * Since: 0.8
95  */
96 void
97 gtk_clutter_get_bg_color (GtkWidget    *widget,
98                           GtkStateType  state,
99                           ClutterColor *color)
100 {
101   g_return_if_fail (GTK_IS_WIDGET (widget));
102   g_return_if_fail (state >= GTK_STATE_NORMAL &&
103                     state <= GTK_STATE_INSENSITIVE);
104   g_return_if_fail (color != NULL);
105
106   gtk_clutter_get_component (widget, GTK_RC_BG, state, color);
107 }
108
109 /**
110  * gtk_clutter_get_text_color:
111  * @widget: a #GtkWidget
112  * @state: a state
113  * @color: return location for a #ClutterColor
114  *
115  * Retrieves the text color of @widget for the given @state and copies it
116  * into @color.
117  *
118  * Since: 0.8
119  */
120 void
121 gtk_clutter_get_text_color (GtkWidget    *widget,
122                             GtkStateType  state,
123                             ClutterColor *color)
124 {
125   g_return_if_fail (GTK_IS_WIDGET (widget));
126   g_return_if_fail (state >= GTK_STATE_NORMAL &&
127                     state <= GTK_STATE_INSENSITIVE);
128   g_return_if_fail (color != NULL);
129
130   gtk_clutter_get_component (widget, GTK_RC_TEXT, state, color);
131 }
132
133 /**
134  * gtk_clutter_get_base_color:
135  * @widget: a #GtkWidget
136  * @state: a state
137  * @color: return location for a #ClutterColor
138  *
139  * Retrieves the base color of @widget for the given @state and copies it
140  * into @color.
141  *
142  * Since: 0.8
143  */
144 void
145 gtk_clutter_get_base_color (GtkWidget    *widget,
146                             GtkStateType  state,
147                             ClutterColor *color)
148 {
149   g_return_if_fail (GTK_IS_WIDGET (widget));
150   g_return_if_fail (state >= GTK_STATE_NORMAL &&
151                     state <= GTK_STATE_INSENSITIVE);
152   g_return_if_fail (color != NULL);
153
154   gtk_clutter_get_component (widget, GTK_RC_BASE, state, color);
155 }
156
157 /**
158  * gtk_clutter_texture_new_from_pixbuf:
159  * @pixbuf: a #GdkPixbuf
160  *
161  * Creates a new #ClutterTexture and sets its contents with a copy
162  * of @pixbuf.
163  *
164  * Return value: the newly created #ClutterTexture
165  *
166  * Since: 0.8
167  */
168 ClutterActor *
169 gtk_clutter_texture_new_from_pixbuf (GdkPixbuf *pixbuf)
170 {
171   ClutterActor *retval;
172   GError *error;
173
174   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
175
176   retval = clutter_texture_new ();
177
178   error = NULL;
179   clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (retval),
180                                      gdk_pixbuf_get_pixels (pixbuf),
181                                      gdk_pixbuf_get_has_alpha (pixbuf),
182                                      gdk_pixbuf_get_width (pixbuf),
183                                      gdk_pixbuf_get_height (pixbuf),
184                                      gdk_pixbuf_get_rowstride (pixbuf),
185                                      4, 0,
186                                      &error);
187   if (error)
188     {
189       g_warning ("Unable to set the pixbuf: %s", error->message);
190       g_error_free (error);
191     }
192
193   return retval; 
194 }
195
196 /**
197  * gtk_clutter_texture_set_from_pixbuf:
198  * @texture: a #ClutterTexture
199  * @pixbuf: a #GdkPixbuf
200  *
201  * Sets the contents of @texture with a copy of @pixbuf.
202  *
203  * Since: 0.8
204  */
205 void
206 gtk_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
207                                      GdkPixbuf      *pixbuf)
208 {
209   GError *error;
210
211   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
212   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
213
214   error = NULL;
215   clutter_texture_set_from_rgb_data (texture,
216                                      gdk_pixbuf_get_pixels (pixbuf),
217                                      gdk_pixbuf_get_has_alpha (pixbuf),
218                                      gdk_pixbuf_get_width (pixbuf),
219                                      gdk_pixbuf_get_height (pixbuf),
220                                      gdk_pixbuf_get_rowstride (pixbuf),
221                                      4, 0,
222                                      &error);
223   if (error)
224     {
225       g_warning ("Unable to set the pixbuf: %s", error->message);
226       g_error_free (error);
227     }
228 }
229
230 /**
231  * gtk_clutter_texture_new_from_stock:
232  * @widget: a #GtkWidget
233  * @stock_id: the stock id of the icon
234  * @size: the size of the icon, or -1
235  *
236  * Creates a new #ClutterTexture and sets its contents using the stock
237  * icon @stock_id as rendered by @widget.
238  *
239  * Return value: the newly created #ClutterTexture
240  *
241  * Since: 0.8
242  */
243 ClutterActor *
244 gtk_clutter_texture_new_from_stock (GtkWidget   *widget,
245                                     const gchar *stock_id,
246                                     GtkIconSize  size)
247 {
248   GdkPixbuf *pixbuf;
249   ClutterActor *retval;
250
251   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
252   g_return_val_if_fail (stock_id != NULL, NULL);
253   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
254
255   pixbuf = gtk_widget_render_icon (widget, stock_id, size, NULL);
256   if (!pixbuf)
257     pixbuf = gtk_widget_render_icon (widget,
258                                      GTK_STOCK_MISSING_IMAGE, size,
259                                      NULL);
260
261   retval = gtk_clutter_texture_new_from_pixbuf (pixbuf);
262   g_object_unref (pixbuf);
263
264   return retval;
265 }
266
267 /**
268  * gtk_clutter_texture_set_from_stock:
269  * @texture: a #ClutterTexture
270  * @widget: a #GtkWidget
271  * @stock_id: the stock id of the icon
272  * @size: the size of the icon, or -1
273  *
274  * Sets the contents of @texture using the stock icon @stock_id, as
275  * rendered by @widget.
276  *
277  * Since: 0.8
278  */
279 void
280 gtk_clutter_texture_set_from_stock (ClutterTexture *texture,
281                                     GtkWidget      *widget,
282                                     const gchar    *stock_id,
283                                     GtkIconSize     size)
284 {
285   GdkPixbuf *pixbuf;
286
287   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
288   g_return_if_fail (GTK_IS_WIDGET (widget));
289   g_return_if_fail (stock_id != NULL);
290   g_return_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1);
291
292   pixbuf = gtk_widget_render_icon (widget, stock_id, size, NULL);
293   if (!pixbuf)
294     pixbuf = gtk_widget_render_icon (widget,
295                                      GTK_STOCK_MISSING_IMAGE, size,
296                                      NULL);
297
298   gtk_clutter_texture_set_from_pixbuf (texture, pixbuf);
299   g_object_unref (pixbuf);
300 }
301
302 /**
303  * gtk_clutter_texture_new_from_icon_name:
304  * @widget: a #GtkWidget or %NULL
305  * @icon_name: the name of the icon
306  * @size: the size of the icon, or -1
307  *
308  * Creates a new #ClutterTexture and sets its contents to be
309  * the @icon_name from the current icon theme.
310  *
311  * Return value: the newly created texture, or %NULL if @widget
312  *   was %NULL and @icon_name was not found.
313  *
314  * Since: 0.8
315  */
316 ClutterActor *
317 gtk_clutter_texture_new_from_icon_name (GtkWidget   *widget,
318                                         const gchar *icon_name,
319                                         GtkIconSize  size)
320 {
321   GtkSettings *settings;
322   GtkIconTheme *icon_theme;
323   gint width, height;
324   GdkPixbuf *pixbuf;
325   GError *error;
326   ClutterActor *retval;
327
328   g_return_val_if_fail (widget == NULL || GTK_IS_WIDGET (widget), NULL);
329   g_return_val_if_fail (icon_name != NULL, NULL);
330   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
331
332   if (widget && gtk_widget_has_screen (widget))
333     {
334       GdkScreen *screen;
335
336       screen = gtk_widget_get_screen (widget);
337       settings = gtk_settings_get_for_screen (screen);
338       icon_theme = gtk_icon_theme_get_for_screen (screen);
339     }
340   else
341     {
342       settings = gtk_settings_get_default ();
343       icon_theme = gtk_icon_theme_get_default ();
344     }
345
346   if (size == -1 ||
347       !gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
348     {
349       width = height = 48;
350     }
351
352   error = NULL;
353   pixbuf = gtk_icon_theme_load_icon (icon_theme,
354                                      icon_name,
355                                      MIN (width, height), 0,
356                                      &error);
357   if (error)
358     {
359       g_warning ("Unable to load the icon `%s' from the theme: %s",
360                  icon_name,
361                  error->message);
362
363       g_error_free (error);
364
365       if (widget)
366         return gtk_clutter_texture_new_from_stock (widget,
367                                              GTK_STOCK_MISSING_IMAGE,
368                                              size);
369       else
370         return NULL;
371     }
372
373   retval = gtk_clutter_texture_new_from_pixbuf (pixbuf);
374   g_object_unref (pixbuf);
375
376   return retval; 
377 }
378
379 /**
380  * gtk_clutter_texture_set_from_icon_name:
381  * @texture: a #ClutterTexture
382  * @widget: a #GtkWidget or %NULL
383  * @icon_name: the name of the icon
384  * @size: the icon size or -1
385  *
386  * Sets the contents of @texture using the @icon_name from the
387  * current icon theme.
388  *
389  * Since: 0.8
390  */
391 void
392 gtk_clutter_texture_set_from_icon_name (ClutterTexture *texture,
393                                         GtkWidget      *widget,
394                                         const gchar    *icon_name,
395                                         GtkIconSize     size)
396 {
397   GtkSettings *settings;
398   GtkIconTheme *icon_theme;
399   gint width, height;
400   GdkPixbuf *pixbuf;
401   GError *error;
402
403   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
404   g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
405   g_return_if_fail (icon_name != NULL);
406   g_return_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1);
407
408   if (widget && gtk_widget_has_screen (widget))
409     {
410       GdkScreen *screen;
411
412       screen = gtk_widget_get_screen (widget);
413       settings = gtk_settings_get_for_screen (screen);
414       icon_theme = gtk_icon_theme_get_for_screen (screen);
415     }
416   else
417     {
418       settings = gtk_settings_get_default ();
419       icon_theme = gtk_icon_theme_get_default ();
420     }
421
422   if (size == -1 ||
423       !gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
424     {
425       width = height = 48;
426     }
427
428   error = NULL;
429   pixbuf = gtk_icon_theme_load_icon (icon_theme,
430                                      icon_name,
431                                      MIN (width, height), 0,
432                                      &error);
433   if (error)
434     {
435       g_warning ("Unable to load the icon `%s' from the theme: %s",
436                  icon_name,
437                  error->message);
438
439       g_error_free (error);
440
441       if (widget)
442         gtk_clutter_texture_set_from_stock (texture,
443                                       widget,
444                                       GTK_STOCK_MISSING_IMAGE,
445                                       size);
446       else
447         return;
448     }
449
450   gtk_clutter_texture_set_from_pixbuf (texture, pixbuf);
451   g_object_unref (pixbuf);
452 }