952058e1690229ff024f38e714acce4824a257d7
[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                                      gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
186                                      0,
187                                      &error);
188   if (error)
189     {
190       g_warning ("Unable to set the pixbuf: %s", error->message);
191       g_error_free (error);
192     }
193
194   return retval; 
195 }
196
197 /**
198  * gtk_clutter_texture_set_from_pixbuf:
199  * @texture: a #ClutterTexture
200  * @pixbuf: a #GdkPixbuf
201  *
202  * Sets the contents of @texture with a copy of @pixbuf.
203  *
204  * Since: 0.8
205  */
206 void
207 gtk_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
208                                      GdkPixbuf      *pixbuf)
209 {
210   GError *error;
211
212   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
213   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
214
215   error = NULL;
216   clutter_texture_set_from_rgb_data (texture,
217                                      gdk_pixbuf_get_pixels (pixbuf),
218                                      gdk_pixbuf_get_has_alpha (pixbuf),
219                                      gdk_pixbuf_get_width (pixbuf),
220                                      gdk_pixbuf_get_height (pixbuf),
221                                      gdk_pixbuf_get_rowstride (pixbuf),
222                                      gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
223                                      0,
224                                      &error);
225   if (error)
226     {
227       g_warning ("Unable to set the pixbuf: %s", error->message);
228       g_error_free (error);
229     }
230 }
231
232 /**
233  * gtk_clutter_texture_new_from_stock:
234  * @widget: a #GtkWidget
235  * @stock_id: the stock id of the icon
236  * @size: the size of the icon, or -1
237  *
238  * Creates a new #ClutterTexture and sets its contents using the stock
239  * icon @stock_id as rendered by @widget.
240  *
241  * Return value: the newly created #ClutterTexture
242  *
243  * Since: 0.8
244  */
245 ClutterActor *
246 gtk_clutter_texture_new_from_stock (GtkWidget   *widget,
247                                     const gchar *stock_id,
248                                     GtkIconSize  size)
249 {
250   GdkPixbuf *pixbuf;
251   ClutterActor *retval;
252
253   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
254   g_return_val_if_fail (stock_id != NULL, NULL);
255   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
256
257   pixbuf = gtk_widget_render_icon (widget, stock_id, size, NULL);
258   if (!pixbuf)
259     pixbuf = gtk_widget_render_icon (widget,
260                                      GTK_STOCK_MISSING_IMAGE, size,
261                                      NULL);
262
263   retval = gtk_clutter_texture_new_from_pixbuf (pixbuf);
264   g_object_unref (pixbuf);
265
266   return retval;
267 }
268
269 /**
270  * gtk_clutter_texture_set_from_stock:
271  * @texture: a #ClutterTexture
272  * @widget: a #GtkWidget
273  * @stock_id: the stock id of the icon
274  * @size: the size of the icon, or -1
275  *
276  * Sets the contents of @texture using the stock icon @stock_id, as
277  * rendered by @widget.
278  *
279  * Since: 0.8
280  */
281 void
282 gtk_clutter_texture_set_from_stock (ClutterTexture *texture,
283                                     GtkWidget      *widget,
284                                     const gchar    *stock_id,
285                                     GtkIconSize     size)
286 {
287   GdkPixbuf *pixbuf;
288
289   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
290   g_return_if_fail (GTK_IS_WIDGET (widget));
291   g_return_if_fail (stock_id != NULL);
292   g_return_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1);
293
294   pixbuf = gtk_widget_render_icon (widget, stock_id, size, NULL);
295   if (!pixbuf)
296     pixbuf = gtk_widget_render_icon (widget,
297                                      GTK_STOCK_MISSING_IMAGE, size,
298                                      NULL);
299
300   gtk_clutter_texture_set_from_pixbuf (texture, pixbuf);
301   g_object_unref (pixbuf);
302 }
303
304 /**
305  * gtk_clutter_texture_new_from_icon_name:
306  * @widget: a #GtkWidget or %NULL
307  * @icon_name: the name of the icon
308  * @size: the size of the icon, or -1
309  *
310  * Creates a new #ClutterTexture and sets its contents to be
311  * the @icon_name from the current icon theme.
312  *
313  * Return value: the newly created texture, or %NULL if @widget
314  *   was %NULL and @icon_name was not found.
315  *
316  * Since: 0.8
317  */
318 ClutterActor *
319 gtk_clutter_texture_new_from_icon_name (GtkWidget   *widget,
320                                         const gchar *icon_name,
321                                         GtkIconSize  size)
322 {
323   GtkSettings *settings;
324   GtkIconTheme *icon_theme;
325   gint width, height;
326   GdkPixbuf *pixbuf;
327   GError *error;
328   ClutterActor *retval;
329
330   g_return_val_if_fail (widget == NULL || GTK_IS_WIDGET (widget), NULL);
331   g_return_val_if_fail (icon_name != NULL, NULL);
332   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
333
334   if (widget && gtk_widget_has_screen (widget))
335     {
336       GdkScreen *screen;
337
338       screen = gtk_widget_get_screen (widget);
339       settings = gtk_settings_get_for_screen (screen);
340       icon_theme = gtk_icon_theme_get_for_screen (screen);
341     }
342   else
343     {
344       settings = gtk_settings_get_default ();
345       icon_theme = gtk_icon_theme_get_default ();
346     }
347
348   if (size == -1 ||
349       !gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
350     {
351       width = height = 48;
352     }
353
354   error = NULL;
355   pixbuf = gtk_icon_theme_load_icon (icon_theme,
356                                      icon_name,
357                                      MIN (width, height), 0,
358                                      &error);
359   if (error)
360     {
361       g_warning ("Unable to load the icon `%s' from the theme: %s",
362                  icon_name,
363                  error->message);
364
365       g_error_free (error);
366
367       if (widget)
368         return gtk_clutter_texture_new_from_stock (widget,
369                                              GTK_STOCK_MISSING_IMAGE,
370                                              size);
371       else
372         return NULL;
373     }
374
375   retval = gtk_clutter_texture_new_from_pixbuf (pixbuf);
376   g_object_unref (pixbuf);
377
378   return retval; 
379 }
380
381 /**
382  * gtk_clutter_texture_set_from_icon_name:
383  * @texture: a #ClutterTexture
384  * @widget: a #GtkWidget or %NULL
385  * @icon_name: the name of the icon
386  * @size: the icon size or -1
387  *
388  * Sets the contents of @texture using the @icon_name from the
389  * current icon theme.
390  *
391  * Since: 0.8
392  */
393 void
394 gtk_clutter_texture_set_from_icon_name (ClutterTexture *texture,
395                                         GtkWidget      *widget,
396                                         const gchar    *icon_name,
397                                         GtkIconSize     size)
398 {
399   GtkSettings *settings;
400   GtkIconTheme *icon_theme;
401   gint width, height;
402   GdkPixbuf *pixbuf;
403   GError *error;
404
405   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
406   g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
407   g_return_if_fail (icon_name != NULL);
408   g_return_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1);
409
410   if (widget && gtk_widget_has_screen (widget))
411     {
412       GdkScreen *screen;
413
414       screen = gtk_widget_get_screen (widget);
415       settings = gtk_settings_get_for_screen (screen);
416       icon_theme = gtk_icon_theme_get_for_screen (screen);
417     }
418   else
419     {
420       settings = gtk_settings_get_default ();
421       icon_theme = gtk_icon_theme_get_default ();
422     }
423
424   if (size == -1 ||
425       !gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
426     {
427       width = height = 48;
428     }
429
430   error = NULL;
431   pixbuf = gtk_icon_theme_load_icon (icon_theme,
432                                      icon_name,
433                                      MIN (width, height), 0,
434                                      &error);
435   if (error)
436     {
437       g_warning ("Unable to load the icon `%s' from the theme: %s",
438                  icon_name,
439                  error->message);
440
441       g_error_free (error);
442
443       if (widget)
444         gtk_clutter_texture_set_from_stock (texture,
445                                       widget,
446                                       GTK_STOCK_MISSING_IMAGE,
447                                       size);
448       else
449         return;
450     }
451
452   gtk_clutter_texture_set_from_pixbuf (texture, pixbuf);
453   g_object_unref (pixbuf);
454 }