ac5272728dbec4d3cc22ad15f72e6600ddd07e9d
[clutter-gtk] / clutter-gtk / gtk-clutter-util.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "gtk-clutter-util.h"
6
7 #include <gdk-pixbuf/gdk-pixbuf.h>
8 #include <gdk/gdk.h>
9 #include <gtk/gtk.h>
10 #include <clutter/clutter.h>
11
12 #if defined(HAVE_CLUTTER_GTK_X11)
13
14 #include <clutter/x11/clutter-x11.h>
15 #include <gdk/gdkx.h>
16
17 #elif defined(HAVE_CLUTTER_GTK_WIN32)
18
19 #include <clutter/clutter-win32.h>
20 #include <gdk/gdkwin32.h>
21
22 #endif /* HAVE_CLUTTER_GTK_{X11,WIN32} */
23
24 /**
25  * SECTION:gtk-clutter-util
26  * @short_description: Utility functions for integrating Clutter in GTK+
27  *
28  * In order to properly integrate a Clutter scene into a GTK+ applications
29  * a certain degree of state must be retrieved from GTK+ itself.
30  *
31  * Clutter-GTK provides API for easing the process of synchronizing colors
32  * with the current GTK+ theme and for loading image sources from #GdkPixbuf,
33  * GTK+ stock items and icon themes.
34  */
35
36 enum
37 {
38   /* base symbols from GtkRcStyle */
39   FG_COMPONENT = GTK_RC_FG,
40   BG_COMPONENT = GTK_RC_BG,
41   TEXT_COMPONENT = GTK_RC_TEXT,
42   BASE_COMPONENT = GTK_RC_BASE,
43
44   /* symbols used by GtkStyle */
45   LIGHT_COMPONENT,
46   MID_COMPONENT,
47   DARK_COMPONENT,
48   TEXT_AA_COMPONENT
49 };
50
51 static inline void
52 gtk_clutter_get_component (GtkWidget    *widget,
53                            gint          component,
54                            GtkStateType  state,
55                            ClutterColor *color)
56 {
57   GtkStyle *style = gtk_widget_get_style (widget);
58   GdkColor gtk_color = { 0, };
59
60   switch (component)
61     {
62     case FG_COMPONENT:
63       gtk_color = style->fg[state];
64       break;
65
66     case BG_COMPONENT:
67       gtk_color = style->bg[state];
68       break;
69
70     case TEXT_COMPONENT:
71       gtk_color = style->text[state];
72       break;
73
74     case BASE_COMPONENT:
75       gtk_color = style->base[state];
76       break;
77
78     case LIGHT_COMPONENT:
79       gtk_color = style->light[state];
80       break;
81
82     case MID_COMPONENT:
83       gtk_color = style->mid[state];
84       break;
85
86     case DARK_COMPONENT:
87       gtk_color = style->dark[state];
88       break;
89
90     case TEXT_AA_COMPONENT:
91       gtk_color = style->text_aa[state];
92       break;
93
94     default:
95       g_assert_not_reached ();
96       break;
97     }
98
99   color->red   = CLAMP (((gtk_color.red   / 65535.0) * 255), 0, 255);
100   color->green = CLAMP (((gtk_color.green / 65535.0) * 255), 0, 255);
101   color->blue  = CLAMP (((gtk_color.blue  / 65535.0) * 255), 0, 255);
102   color->alpha = 255;
103 }
104
105 /**
106  * gtk_clutter_get_fg_color:
107  * @widget: a #GtkWidget
108  * @state: a state
109  * @color: return location for a #ClutterColor
110  *
111  * Retrieves the foreground color of @widget for the given @state and copies
112  * it into @color.
113  *
114  * Since: 0.8
115  */
116 void
117 gtk_clutter_get_fg_color (GtkWidget    *widget,
118                           GtkStateType  state,
119                           ClutterColor *color)
120 {
121   g_return_if_fail (GTK_IS_WIDGET (widget));
122   g_return_if_fail (state >= GTK_STATE_NORMAL &&
123                     state <= GTK_STATE_INSENSITIVE);
124   g_return_if_fail (color != NULL);
125
126   gtk_clutter_get_component (widget, FG_COMPONENT, state, color);
127 }
128
129 /**
130  * gtk_clutter_get_bg_color:
131  * @widget: a #GtkWidget
132  * @state: a state
133  * @color: return location for a #ClutterColor
134  *
135  * Retrieves the background color of @widget for the given @state and copies
136  * it into @color.
137  *
138  * Since: 0.8
139  */
140 void
141 gtk_clutter_get_bg_color (GtkWidget    *widget,
142                           GtkStateType  state,
143                           ClutterColor *color)
144 {
145   g_return_if_fail (GTK_IS_WIDGET (widget));
146   g_return_if_fail (state >= GTK_STATE_NORMAL &&
147                     state <= GTK_STATE_INSENSITIVE);
148   g_return_if_fail (color != NULL);
149
150   gtk_clutter_get_component (widget, BG_COMPONENT, state, color);
151 }
152
153 /**
154  * gtk_clutter_get_text_color:
155  * @widget: a #GtkWidget
156  * @state: a state
157  * @color: return location for a #ClutterColor
158  *
159  * Retrieves the text color of @widget for the given @state and copies it
160  * into @color.
161  *
162  * Since: 0.8
163  */
164 void
165 gtk_clutter_get_text_color (GtkWidget    *widget,
166                             GtkStateType  state,
167                             ClutterColor *color)
168 {
169   g_return_if_fail (GTK_IS_WIDGET (widget));
170   g_return_if_fail (state >= GTK_STATE_NORMAL &&
171                     state <= GTK_STATE_INSENSITIVE);
172   g_return_if_fail (color != NULL);
173
174   gtk_clutter_get_component (widget, TEXT_COMPONENT, state, color);
175 }
176
177 /**
178  * gtk_clutter_get_base_color:
179  * @widget: a #GtkWidget
180  * @state: a state
181  * @color: return location for a #ClutterColor
182  *
183  * Retrieves the base color of @widget for the given @state and copies it
184  * into @color.
185  *
186  * Since: 0.8
187  */
188 void
189 gtk_clutter_get_base_color (GtkWidget    *widget,
190                             GtkStateType  state,
191                             ClutterColor *color)
192 {
193   g_return_if_fail (GTK_IS_WIDGET (widget));
194   g_return_if_fail (state >= GTK_STATE_NORMAL &&
195                     state <= GTK_STATE_INSENSITIVE);
196   g_return_if_fail (color != NULL);
197
198   gtk_clutter_get_component (widget, BASE_COMPONENT, state, color);
199 }
200
201 /**
202  * gtk_clutter_get_light_color:
203  * @widget: a #GtkWidget
204  * @state: a state
205  * @color: return location for a #ClutterColor
206  *
207  * Retrieves the light color of @widget for the given @state and copies it
208  * into @color.
209  *
210  * Since: 0.8
211  */
212 void
213 gtk_clutter_get_light_color (GtkWidget    *widget,
214                              GtkStateType  state,
215                              ClutterColor *color)
216 {
217   g_return_if_fail (GTK_IS_WIDGET (widget));
218   g_return_if_fail (state >= GTK_STATE_NORMAL &&
219                     state <= GTK_STATE_INSENSITIVE);
220   g_return_if_fail (color != NULL);
221
222   gtk_clutter_get_component (widget, LIGHT_COMPONENT, state, color);
223 }
224
225 /**
226  * gtk_clutter_get_mid_color:
227  * @widget: a #GtkWidget
228  * @state: a state
229  * @color: return location for a #ClutterColor
230  *
231  * Retrieves the mid color of @widget for the given @state and copies it
232  * into @color.
233  *
234  * Since: 0.8
235  */
236 void
237 gtk_clutter_get_mid_color (GtkWidget    *widget,
238                            GtkStateType  state,
239                            ClutterColor *color)
240 {
241   g_return_if_fail (GTK_IS_WIDGET (widget));
242   g_return_if_fail (state >= GTK_STATE_NORMAL &&
243                     state <= GTK_STATE_INSENSITIVE);
244   g_return_if_fail (color != NULL);
245
246   gtk_clutter_get_component (widget, MID_COMPONENT, state, color);
247 }
248
249 /**
250  * gtk_clutter_get_dark_color:
251  * @widget: a #GtkWidget
252  * @state: a state
253  * @color: return location for a #ClutterColor
254  *
255  * Retrieves the dark color of @widget for the given @state and copies it
256  * into @color.
257  *
258  * Since: 0.8
259  */
260 void
261 gtk_clutter_get_dark_color (GtkWidget    *widget,
262                             GtkStateType  state,
263                             ClutterColor *color)
264 {
265   g_return_if_fail (GTK_IS_WIDGET (widget));
266   g_return_if_fail (state >= GTK_STATE_NORMAL &&
267                     state <= GTK_STATE_INSENSITIVE);
268   g_return_if_fail (color != NULL);
269
270   gtk_clutter_get_component (widget, DARK_COMPONENT, state, color);
271 }
272
273 /**
274  * gtk_clutter_get_text_aa_color:
275  * @widget: a #GtkWidget
276  * @state: a state
277  * @color: return location for a #ClutterColor
278  *
279  * Retrieves the text-aa color of @widget for the given @state and copies it
280  * into @color.
281  *
282  * Since: 0.8
283  */
284 void
285 gtk_clutter_get_text_aa_color (GtkWidget    *widget,
286                                GtkStateType  state,
287                                ClutterColor *color)
288 {
289   g_return_if_fail (GTK_IS_WIDGET (widget));
290   g_return_if_fail (state >= GTK_STATE_NORMAL &&
291                     state <= GTK_STATE_INSENSITIVE);
292   g_return_if_fail (color != NULL);
293
294   gtk_clutter_get_component (widget, TEXT_AA_COMPONENT, state, color);
295 }
296
297 /**
298  * gtk_clutter_texture_new_from_pixbuf:
299  * @pixbuf: a #GdkPixbuf
300  *
301  * Creates a new #ClutterTexture and sets its contents with a copy
302  * of @pixbuf.
303  *
304  * Return value: the newly created #ClutterTexture
305  *
306  * Since: 0.8
307  */
308 ClutterActor *
309 gtk_clutter_texture_new_from_pixbuf (GdkPixbuf *pixbuf)
310 {
311   ClutterActor *retval;
312   GError *error;
313
314   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
315
316   retval = clutter_texture_new ();
317
318   error = NULL;
319   clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (retval),
320                                      gdk_pixbuf_get_pixels (pixbuf),
321                                      gdk_pixbuf_get_has_alpha (pixbuf),
322                                      gdk_pixbuf_get_width (pixbuf),
323                                      gdk_pixbuf_get_height (pixbuf),
324                                      gdk_pixbuf_get_rowstride (pixbuf),
325                                      gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
326                                      0,
327                                      &error);
328   if (error)
329     {
330       g_warning ("Unable to set the pixbuf: %s", error->message);
331       g_error_free (error);
332     }
333
334   return retval; 
335 }
336
337 /**
338  * gtk_clutter_texture_set_from_pixbuf:
339  * @texture: a #ClutterTexture
340  * @pixbuf: a #GdkPixbuf
341  *
342  * Sets the contents of @texture with a copy of @pixbuf.
343  *
344  * Since: 0.8
345  */
346 void
347 gtk_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
348                                      GdkPixbuf      *pixbuf)
349 {
350   GError *error;
351
352   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
353   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
354
355   error = NULL;
356   clutter_texture_set_from_rgb_data (texture,
357                                      gdk_pixbuf_get_pixels (pixbuf),
358                                      gdk_pixbuf_get_has_alpha (pixbuf),
359                                      gdk_pixbuf_get_width (pixbuf),
360                                      gdk_pixbuf_get_height (pixbuf),
361                                      gdk_pixbuf_get_rowstride (pixbuf),
362                                      gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
363                                      0,
364                                      &error);
365   if (error)
366     {
367       g_warning ("Unable to set the pixbuf: %s", error->message);
368       g_error_free (error);
369     }
370 }
371
372 /**
373  * gtk_clutter_texture_new_from_stock:
374  * @widget: a #GtkWidget
375  * @stock_id: the stock id of the icon
376  * @size: the size of the icon, or -1
377  *
378  * Creates a new #ClutterTexture and sets its contents using the stock
379  * icon @stock_id as rendered by @widget.
380  *
381  * Return value: the newly created #ClutterTexture
382  *
383  * Since: 0.8
384  */
385 ClutterActor *
386 gtk_clutter_texture_new_from_stock (GtkWidget   *widget,
387                                     const gchar *stock_id,
388                                     GtkIconSize  size)
389 {
390   GdkPixbuf *pixbuf;
391   ClutterActor *retval;
392
393   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
394   g_return_val_if_fail (stock_id != NULL, NULL);
395   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
396
397   pixbuf = gtk_widget_render_icon (widget, stock_id, size, NULL);
398   if (!pixbuf)
399     pixbuf = gtk_widget_render_icon (widget,
400                                      GTK_STOCK_MISSING_IMAGE, size,
401                                      NULL);
402
403   retval = gtk_clutter_texture_new_from_pixbuf (pixbuf);
404   g_object_unref (pixbuf);
405
406   return retval;
407 }
408
409 /**
410  * gtk_clutter_texture_set_from_stock:
411  * @texture: a #ClutterTexture
412  * @widget: a #GtkWidget
413  * @stock_id: the stock id of the icon
414  * @size: the size of the icon, or -1
415  *
416  * Sets the contents of @texture using the stock icon @stock_id, as
417  * rendered by @widget.
418  *
419  * Since: 0.8
420  */
421 void
422 gtk_clutter_texture_set_from_stock (ClutterTexture *texture,
423                                     GtkWidget      *widget,
424                                     const gchar    *stock_id,
425                                     GtkIconSize     size)
426 {
427   GdkPixbuf *pixbuf;
428
429   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
430   g_return_if_fail (GTK_IS_WIDGET (widget));
431   g_return_if_fail (stock_id != NULL);
432   g_return_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1);
433
434   pixbuf = gtk_widget_render_icon (widget, stock_id, size, NULL);
435   if (!pixbuf)
436     pixbuf = gtk_widget_render_icon (widget,
437                                      GTK_STOCK_MISSING_IMAGE, size,
438                                      NULL);
439
440   gtk_clutter_texture_set_from_pixbuf (texture, pixbuf);
441   g_object_unref (pixbuf);
442 }
443
444 /**
445  * gtk_clutter_texture_new_from_icon_name:
446  * @widget: a #GtkWidget or %NULL
447  * @icon_name: the name of the icon
448  * @size: the size of the icon, or -1
449  *
450  * Creates a new #ClutterTexture and sets its contents to be
451  * the @icon_name from the current icon theme.
452  *
453  * Return value: the newly created texture, or %NULL if @widget
454  *   was %NULL and @icon_name was not found.
455  *
456  * Since: 0.8
457  */
458 ClutterActor *
459 gtk_clutter_texture_new_from_icon_name (GtkWidget   *widget,
460                                         const gchar *icon_name,
461                                         GtkIconSize  size)
462 {
463   GtkSettings *settings;
464   GtkIconTheme *icon_theme;
465   gint width, height;
466   GdkPixbuf *pixbuf;
467   GError *error;
468   ClutterActor *retval;
469
470   g_return_val_if_fail (widget == NULL || GTK_IS_WIDGET (widget), NULL);
471   g_return_val_if_fail (icon_name != NULL, NULL);
472   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
473
474   if (widget && gtk_widget_has_screen (widget))
475     {
476       GdkScreen *screen;
477
478       screen = gtk_widget_get_screen (widget);
479       settings = gtk_settings_get_for_screen (screen);
480       icon_theme = gtk_icon_theme_get_for_screen (screen);
481     }
482   else
483     {
484       settings = gtk_settings_get_default ();
485       icon_theme = gtk_icon_theme_get_default ();
486     }
487
488   if (size == -1 ||
489       !gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
490     {
491       width = height = 48;
492     }
493
494   error = NULL;
495   pixbuf = gtk_icon_theme_load_icon (icon_theme,
496                                      icon_name,
497                                      MIN (width, height), 0,
498                                      &error);
499   if (error)
500     {
501       g_warning ("Unable to load the icon `%s' from the theme: %s",
502                  icon_name,
503                  error->message);
504
505       g_error_free (error);
506
507       if (widget)
508         return gtk_clutter_texture_new_from_stock (widget,
509                                              GTK_STOCK_MISSING_IMAGE,
510                                              size);
511       else
512         return NULL;
513     }
514
515   retval = gtk_clutter_texture_new_from_pixbuf (pixbuf);
516   g_object_unref (pixbuf);
517
518   return retval; 
519 }
520
521 /**
522  * gtk_clutter_texture_set_from_icon_name:
523  * @texture: a #ClutterTexture
524  * @widget: a #GtkWidget or %NULL
525  * @icon_name: the name of the icon
526  * @size: the icon size or -1
527  *
528  * Sets the contents of @texture using the @icon_name from the
529  * current icon theme.
530  *
531  * Since: 0.8
532  */
533 void
534 gtk_clutter_texture_set_from_icon_name (ClutterTexture *texture,
535                                         GtkWidget      *widget,
536                                         const gchar    *icon_name,
537                                         GtkIconSize     size)
538 {
539   GtkSettings *settings;
540   GtkIconTheme *icon_theme;
541   gint width, height;
542   GdkPixbuf *pixbuf;
543   GError *error;
544
545   g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
546   g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
547   g_return_if_fail (icon_name != NULL);
548   g_return_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1);
549
550   if (widget && gtk_widget_has_screen (widget))
551     {
552       GdkScreen *screen;
553
554       screen = gtk_widget_get_screen (widget);
555       settings = gtk_settings_get_for_screen (screen);
556       icon_theme = gtk_icon_theme_get_for_screen (screen);
557     }
558   else
559     {
560       settings = gtk_settings_get_default ();
561       icon_theme = gtk_icon_theme_get_default ();
562     }
563
564   if (size == -1 ||
565       !gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
566     {
567       width = height = 48;
568     }
569
570   error = NULL;
571   pixbuf = gtk_icon_theme_load_icon (icon_theme,
572                                      icon_name,
573                                      MIN (width, height), 0,
574                                      &error);
575   if (error)
576     {
577       g_warning ("Unable to load the icon `%s' from the theme: %s",
578                  icon_name,
579                  error->message);
580
581       g_error_free (error);
582
583       if (widget)
584         gtk_clutter_texture_set_from_stock (texture,
585                                       widget,
586                                       GTK_STOCK_MISSING_IMAGE,
587                                       size);
588       else
589         return;
590     }
591
592   gtk_clutter_texture_set_from_pixbuf (texture, pixbuf);
593   g_object_unref (pixbuf);
594 }
595
596 /**
597  * gtk_clutter_init:
598  * @argc: pointer to the arguments count, or %NULL
599  * @argv: pointer to the arguments vector, or %NULL
600  *
601  * This function should be called instead of clutter_init() and
602  * gtk_init().
603  *
604  * Return value: %CLUTTER_INIT_SUCCESS on success, a negative integer
605  *   on failure.
606  *
607  * Since: 0.8
608  */
609 ClutterInitError
610 gtk_clutter_init (int    *argc,
611                   char ***argv)
612 {
613   if (!gtk_init_check (argc, argv))
614     return CLUTTER_INIT_ERROR_GTK;
615
616 #if defined(HAVE_CLUTTER_GTK_X11)
617   clutter_x11_set_display (GDK_DISPLAY());
618   clutter_x11_disable_event_retrieval ();
619 #elif defined(HAVE_CLUTTER_GTK_WIN32)
620   clutter_win32_disable_event_retrieval ();
621 #endif /* HAVE_CLUTTER_GTK_{X11,WIN32} */
622
623   return clutter_init (argc, argv);
624 }
625
626 /**
627  * gtk_clutter_init_with_args:
628  * @argc: a pointer to the number of command line arguments.
629  * @argv: a pointer to the array of command line arguments.
630  * @parameter_string: a string which is displayed in
631  *    the first line of <option>--help</option> output, after
632  *    <literal><replaceable>programname</replaceable> [OPTION...]</literal>
633  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
634  *    describing the options of your program
635  * @translation_domain: a translation domain to use for translating
636  *    the <option>--help</option> output for the options in @entries
637  *    with gettext(), or %NULL
638  * @error: a return location for errors
639  *
640  * This function should be called instead of clutter_init() and
641  * gtk_init_with_args().
642  *
643  * Return value: %CLUTTER_INIT_SUCCESS on success, a negative integer
644  *   on failure.
645  *
646  * Since: 1.0
647  */
648 ClutterInitError
649 gtk_clutter_init_with_args (int            *argc,
650                             char         ***argv,
651                             const char     *parameter_string,
652                             GOptionEntry   *entries,
653                             const char     *translation_domain,
654                             GError        **error)
655 {
656   gboolean res;
657
658   res = gtk_init_with_args (argc, argv,
659                             (char*) parameter_string,
660                             entries,
661                             (char*) translation_domain,
662                             error);
663
664   if (!res)
665     return CLUTTER_INIT_ERROR_GTK;
666
667 #if defined(GDK_WINDOWING_X11)
668   clutter_x11_set_display (GDK_DISPLAY());
669   clutter_x11_disable_event_retrieval ();
670 #elif defined(GDK_WINDOWING_WIN32)
671   clutter_win32_disable_event_retrieval ();
672 #endif /* GDK_WINDOWING_{X11,WIN32} */
673
674   return clutter_init_with_args (argc, argv,
675                                  NULL,
676                                  NULL,
677                                  NULL,
678                                  error);
679 }