Updated Finnish translation
[rhythmbox.git] / lib / rb-util.c
blob852ae9f0b3104559967e4af3dd01cef591d266c2
1 /*
2 * arch-tag: Implementation of totally random functions that didn't fit elsewhere
4 * Copyright (C) 2003 Colin Walters <walters@verbum.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "config.h"
23 #include <string.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
27 #include <gtk/gtk.h>
28 #include <libgnome/gnome-i18n.h>
29 #include <libgnomevfs/gnome-vfs.h>
30 #include <libgnomevfs/gnome-vfs-mime-handlers.h>
31 #include <gobject/gvaluecollector.h>
33 #include "rb-util.h"
34 #include "rb-debug.h"
36 static GPrivate * private_is_primary_thread;
38 gboolean
39 rb_true_function (gpointer dummy)
41 return TRUE;
44 gboolean
45 rb_false_function (gpointer dummy)
47 return FALSE;
50 gpointer
51 rb_null_function (gpointer dummy)
53 return NULL;
56 gpointer
57 rb_copy_function (gpointer data)
59 return data;
63 int
64 rb_gvalue_compare (GValue *a, GValue *b)
66 int retval;
67 const char *stra, *strb;
69 if (G_VALUE_TYPE (a) != G_VALUE_TYPE (b))
70 return -1;
72 switch (G_VALUE_TYPE (a))
74 case G_TYPE_BOOLEAN:
75 if (g_value_get_int (a) < g_value_get_int (b))
76 retval = -1;
77 else if (g_value_get_int (a) == g_value_get_int (b))
78 retval = 0;
79 else
80 retval = 1;
81 break;
82 case G_TYPE_CHAR:
83 if (g_value_get_char (a) < g_value_get_char (b))
84 retval = -1;
85 else if (g_value_get_char (a) == g_value_get_char (b))
86 retval = 0;
87 else
88 retval = 1;
89 break;
90 case G_TYPE_UCHAR:
91 if (g_value_get_uchar (a) < g_value_get_uchar (b))
92 retval = -1;
93 else if (g_value_get_uchar (a) == g_value_get_uchar (b))
94 retval = 0;
95 else
96 retval = 1;
97 break;
98 case G_TYPE_INT:
99 if (g_value_get_int (a) < g_value_get_int (b))
100 retval = -1;
101 else if (g_value_get_int (a) == g_value_get_int (b))
102 retval = 0;
103 else
104 retval = 1;
105 break;
106 case G_TYPE_UINT:
107 if (g_value_get_uint (a) < g_value_get_uint (b))
108 retval = -1;
109 else if (g_value_get_uint (a) == g_value_get_uint (b))
110 retval = 0;
111 else
112 retval = 1;
113 break;
114 case G_TYPE_LONG:
115 if (g_value_get_long (a) < g_value_get_long (b))
116 retval = -1;
117 else if (g_value_get_long (a) == g_value_get_long (b))
118 retval = 0;
119 else
120 retval = 1;
121 break;
122 case G_TYPE_ULONG:
123 if (g_value_get_ulong (a) < g_value_get_ulong (b))
124 retval = -1;
125 else if (g_value_get_ulong (a) == g_value_get_ulong (b))
126 retval = 0;
127 else
128 retval = 1;
129 break;
130 case G_TYPE_INT64:
131 if (g_value_get_int64 (a) < g_value_get_int64 (b))
132 retval = -1;
133 else if (g_value_get_int64 (a) == g_value_get_int64 (b))
134 retval = 0;
135 else
136 retval = 1;
137 break;
138 case G_TYPE_UINT64:
139 if (g_value_get_uint64 (a) < g_value_get_uint64 (b))
140 retval = -1;
141 else if (g_value_get_uint64 (a) == g_value_get_uint64 (b))
142 retval = 0;
143 else
144 retval = 1;
145 break;
146 case G_TYPE_ENUM:
147 /* this is somewhat bogus. */
148 if (g_value_get_enum (a) < g_value_get_enum (b))
149 retval = -1;
150 else if (g_value_get_enum (a) == g_value_get_enum (b))
151 retval = 0;
152 else
153 retval = 1;
154 break;
155 case G_TYPE_FLAGS:
156 /* this is even more bogus. */
157 if (g_value_get_flags (a) < g_value_get_flags (b))
158 retval = -1;
159 else if (g_value_get_flags (a) == g_value_get_flags (b))
160 retval = 0;
161 else
162 retval = 1;
163 break;
164 case G_TYPE_FLOAT:
165 if (g_value_get_float (a) < g_value_get_float (b))
166 retval = -1;
167 else if (g_value_get_float (a) == g_value_get_float (b))
168 retval = 0;
169 else
170 retval = 1;
171 break;
172 case G_TYPE_DOUBLE:
173 if (g_value_get_double (a) < g_value_get_double (b))
174 retval = -1;
175 else if (g_value_get_double (a) == g_value_get_double (b))
176 retval = 0;
177 else
178 retval = 1;
179 break;
180 case G_TYPE_STRING:
181 stra = g_value_get_string (a);
182 strb = g_value_get_string (b);
183 if (stra == NULL) stra = "";
184 if (strb == NULL) strb = "";
185 retval = g_utf8_collate (stra, strb);
186 break;
187 case G_TYPE_POINTER:
188 retval = (g_value_get_pointer (a) != g_value_get_pointer (b));
189 break;
190 case G_TYPE_BOXED:
191 retval = (g_value_get_boxed (a) != g_value_get_boxed (b));
192 break;
193 case G_TYPE_OBJECT:
194 retval = (g_value_get_object (a) != g_value_get_object (b));
195 break;
196 default:
197 g_assert_not_reached ();
198 retval = 0;
199 break;
201 return retval;
205 rb_compare_gtimeval (GTimeVal *a, GTimeVal *b)
207 if (a->tv_sec == b->tv_sec)
208 /* It's quite unlikely that microseconds are equal,
209 * so just ignore that case, we don't need a lot
210 * of precision.
212 return a->tv_usec > b->tv_usec ? 1 : -1;
213 else if (a->tv_sec > b->tv_sec)
214 return 1;
215 else
216 return -1;
219 /* Taken from totem/video-utils.c CVS HEAD 2004-04-22 */
220 static void
221 totem_pixbuf_mirror (GdkPixbuf *pixbuf)
223 int i, j, rowstride, offset, right;
224 guchar *pixels;
225 int width, height, size;
226 guint32 tmp;
228 pixels = gdk_pixbuf_get_pixels (pixbuf);
229 g_return_if_fail (pixels != NULL);
231 width = gdk_pixbuf_get_width (pixbuf);
232 height = gdk_pixbuf_get_height (pixbuf);
233 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
234 size = height * width * sizeof (guint32);
236 for (i = 0; i < size; i += rowstride)
238 for (j = 0; j < rowstride; j += sizeof(guint32))
240 offset = i + j;
241 right = i + (((width - 1) * sizeof(guint32)) - j);
243 if (right <= offset)
244 break;
246 memcpy (&tmp, pixels + offset, sizeof(guint32));
247 memcpy (pixels + offset, pixels + right,
248 sizeof(guint32));
249 memcpy (pixels + right, &tmp, sizeof(guint32));
256 /* Same as gtk_image_new_from_stock except that it mirrors the icons for RTL
257 * languages
259 GtkWidget *
260 rb_image_new_from_stock (const gchar *stock_id, GtkIconSize size)
263 if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR) {
264 return gtk_image_new_from_stock (stock_id, size);
265 } else {
267 GtkWidget *image;
268 GdkPixbuf *pixbuf;
269 GdkPixbuf *mirror;
271 image = gtk_image_new ();
273 if (image == NULL) {
274 return NULL;
277 pixbuf = gtk_widget_render_icon (image, stock_id, size, NULL);
278 g_assert (pixbuf != NULL);
281 mirror = gdk_pixbuf_copy (pixbuf);
282 gdk_pixbuf_unref (pixbuf);
284 if (!mirror)
285 return NULL;
287 totem_pixbuf_mirror (mirror);
288 gtk_image_set_from_pixbuf (GTK_IMAGE (image), mirror);
289 gdk_pixbuf_unref (mirror);
291 return image;
294 return NULL;
297 void
298 rb_gtk_action_popup_menu (GtkUIManager *uimanager, const char *path)
300 GtkWidget *menu;
302 menu = gtk_ui_manager_get_widget (uimanager, path);
303 if (menu == NULL) {
304 g_warning ("Couldn't get menu widget for %s", path);
305 } else {
306 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3,
307 gtk_get_current_event_time ());
311 static GList *
312 get_mount_points (void)
314 GnomeVFSVolumeMonitor *monitor;
315 GList *volumes;
316 GList *it;
317 GList *mount_points = NULL;
319 monitor = gnome_vfs_get_volume_monitor ();
320 /* FIXME: should also get the list of connected drivers (network
321 * shares I assume)
323 volumes = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
325 for (it = volumes; it != NULL; it = it->next) {
326 gchar *uri;
327 GnomeVFSVolume *volume;
329 volume = GNOME_VFS_VOLUME (it->data);
330 uri = gnome_vfs_volume_get_activation_uri (volume);
331 g_assert (uri != NULL);
332 mount_points = g_list_prepend (mount_points, uri);
335 g_list_foreach (volumes, (GFunc)gnome_vfs_volume_ref, NULL);
336 g_list_free (volumes);
338 return mount_points;
342 gchar *
343 rb_uri_get_mount_point (const char *uri)
345 GList *mount_points = get_mount_points ();
346 GList *it;
347 gchar *mount_point = NULL;
349 for (it = mount_points; it != NULL; it = it->next) {
350 if (g_str_has_prefix (uri, it->data)) {
351 if ((mount_point == NULL) || (strlen (mount_point) < strlen (it->data))) {
352 g_free (mount_point);
353 mount_point = g_strdup (it->data);
357 g_list_foreach (mount_points, (GFunc)g_free, NULL);
358 g_list_free (mount_points);
360 return mount_point;
363 gboolean
364 rb_uri_is_mounted (const char *uri)
366 GList *mount_points = get_mount_points ();
367 GList *it;
368 gboolean found = FALSE;
370 if ((uri == NULL) || (*uri == '\0')) {
371 return TRUE;
374 for (it = mount_points; it != NULL; it = it->next) {
375 if (strcmp (it->data, uri) == 0) {
376 found = TRUE;
377 break;
380 g_list_foreach (mount_points, (GFunc)g_free, NULL);
381 g_list_free (mount_points);
383 /* if (found == FALSE) {
384 g_print ("%s not mounted\n", uri);
387 return found;
390 gboolean
391 rb_is_main_thread (void)
393 if (g_thread_supported()) {
394 return GPOINTER_TO_UINT(g_private_get (private_is_primary_thread)) == 1;
395 } else {
396 return TRUE;
400 static gboolean
401 purge_useless_threads (gpointer data)
403 g_thread_pool_stop_unused_threads ();
404 return TRUE;
407 void
408 rb_threads_init (void)
410 private_is_primary_thread = g_private_new (NULL);
411 g_private_set (private_is_primary_thread, GUINT_TO_POINTER (1));
413 /* not really necessary, but in case it does something besides
414 * set up lock functions some day..
416 gdk_threads_init ();
418 /* purge useless thread-pool threads occasionally */
419 g_timeout_add (30 * 1000, purge_useless_threads, NULL);
422 gchar **
423 rb_string_split_words (const gchar *string)
425 /*return g_slist_prepend (NULL, g_strdup (string));*/
427 GSList *words, *current;
428 gunichar *unicode, *cur_write, *cur_read;
429 gchar **ret;
430 gint i, wordcount = 1;
431 gboolean new_word = TRUE;
433 g_return_val_if_fail (string != NULL, NULL);
435 cur_write = cur_read = unicode = g_utf8_to_ucs4_fast (string, -1, NULL);
437 /* we may fail here, we expect valid utf-8 */
438 g_return_val_if_fail (unicode != NULL, NULL);
440 words = g_slist_prepend (NULL, unicode);
442 /* now normalize this text */
443 while (*cur_read) {
444 switch (g_unichar_type (*cur_read)) {
445 case G_UNICODE_UNASSIGNED:
446 rb_debug ("unassigned unicode character type found");
447 /* fall through */
448 case G_UNICODE_CONTROL:
449 case G_UNICODE_FORMAT:
450 case G_UNICODE_PRIVATE_USE:
452 case G_UNICODE_SURROGATE:
453 case G_UNICODE_LINE_SEPARATOR:
454 case G_UNICODE_PARAGRAPH_SEPARATOR:
455 case G_UNICODE_SPACE_SEPARATOR:
456 /* remove these and start a new word */
457 if (!new_word) {
458 /* end current word if it isn't ended yet */
459 *cur_write++ = 0;
460 new_word = TRUE;
463 break;
464 case G_UNICODE_COMBINING_MARK:
465 case G_UNICODE_ENCLOSING_MARK:
466 case G_UNICODE_NON_SPACING_MARK:
467 case G_UNICODE_CONNECT_PUNCTUATION:
468 case G_UNICODE_DASH_PUNCTUATION:
469 case G_UNICODE_CLOSE_PUNCTUATION:
470 case G_UNICODE_FINAL_PUNCTUATION:
471 case G_UNICODE_INITIAL_PUNCTUATION:
472 case G_UNICODE_OTHER_PUNCTUATION:
473 case G_UNICODE_OPEN_PUNCTUATION:
474 /* remove these */
475 /*break;*/
476 case G_UNICODE_LOWERCASE_LETTER:
477 case G_UNICODE_MODIFIER_LETTER:
478 case G_UNICODE_OTHER_LETTER:
479 case G_UNICODE_TITLECASE_LETTER:
480 case G_UNICODE_UPPERCASE_LETTER:
481 case G_UNICODE_DECIMAL_NUMBER:
482 case G_UNICODE_LETTER_NUMBER:
483 case G_UNICODE_OTHER_NUMBER:
484 case G_UNICODE_CURRENCY_SYMBOL:
485 case G_UNICODE_MODIFIER_SYMBOL:
486 case G_UNICODE_MATH_SYMBOL:
487 case G_UNICODE_OTHER_SYMBOL:
488 /* keep these unchanged */
489 *cur_write = *cur_read;
490 if (new_word) {
491 if (cur_write != unicode) {/* first insert has been done above */
492 words = g_slist_prepend (words, cur_write);
493 wordcount++;
495 new_word = FALSE;
497 cur_write++;
498 break;
499 default:
500 g_warning ("unknown unicode character type found");
501 break;
503 cur_read++;
506 if (!new_word) {
507 *cur_write++ = 0;
510 ret = g_new (gchar *, wordcount + 1);
511 current = words;
512 for (i = wordcount - 1; i >= 0; i--) {
513 ret[i] = g_ucs4_to_utf8 (current->data, -1, NULL, NULL, NULL);
514 current = g_slist_next (current);
516 ret[wordcount] = NULL;
518 g_slist_free (words);
519 g_free (unicode);
521 return ret;
524 gchar*
525 rb_search_fold (const char *original)
527 GString *string;
528 gunichar *unicode, *cur;
530 g_return_val_if_fail (original != NULL, NULL);
532 /* old behaviour is equivalent to: return g_utf8_casefold (original, -1); */
534 string = g_string_new (NULL);
535 unicode = g_utf8_to_ucs4_fast (original, -1, NULL);
537 for (cur = unicode; *cur != 0; cur++) {
538 switch (g_unichar_type (*cur)) {
539 case G_UNICODE_COMBINING_MARK:
540 case G_UNICODE_ENCLOSING_MARK:
541 case G_UNICODE_NON_SPACING_MARK:
542 case G_UNICODE_CONNECT_PUNCTUATION:
543 case G_UNICODE_DASH_PUNCTUATION:
544 case G_UNICODE_CLOSE_PUNCTUATION:
545 case G_UNICODE_FINAL_PUNCTUATION:
546 case G_UNICODE_INITIAL_PUNCTUATION:
547 case G_UNICODE_OTHER_PUNCTUATION:
548 case G_UNICODE_OPEN_PUNCTUATION:
549 /* remove these */
550 break;
552 case G_UNICODE_LOWERCASE_LETTER:
553 case G_UNICODE_MODIFIER_LETTER:
554 case G_UNICODE_OTHER_LETTER:
555 case G_UNICODE_TITLECASE_LETTER:
556 case G_UNICODE_UPPERCASE_LETTER:
557 /* convert to lower case */
558 *cur = g_unichar_tolower (*cur);
559 /* ... and fall through */\
560 case G_UNICODE_DECIMAL_NUMBER:
561 case G_UNICODE_LETTER_NUMBER:
562 case G_UNICODE_OTHER_NUMBER:
563 /* should be keep symbols? */
564 case G_UNICODE_CURRENCY_SYMBOL:
565 case G_UNICODE_MODIFIER_SYMBOL:
566 case G_UNICODE_MATH_SYMBOL:
567 case G_UNICODE_OTHER_SYMBOL:
568 g_string_append_unichar (string, *cur);
569 break;
571 case G_UNICODE_UNASSIGNED:
572 rb_debug ("unassigned unicode character type found");
573 /* fall through */
575 default:
576 /* leave these in */
577 g_string_append_unichar (string, *cur);
581 g_free (unicode);
583 return g_string_free (string, FALSE);
586 char *
587 rb_make_duration_string (guint duration)
589 char *str;
590 int hours, minutes, seconds;
592 hours = duration / (60 * 60);
593 minutes = (duration - (hours * 60 * 60)) / 60;
594 seconds = duration % 60;
596 if (hours == 0 && minutes == 0 && seconds == 0)
597 str = g_strdup (_("Unknown"));
598 else if (hours == 0)
599 str = g_strdup_printf (_("%d:%02d"), minutes, seconds);
600 else
601 str = g_strdup_printf (_("%d:%02d:%02d"), hours, minutes, seconds);
603 return str;
606 char *
607 rb_make_elapsed_time_string (guint elapsed, guint duration, gboolean show_remaining)
609 int seconds = 0, minutes = 0, hours = 0;
610 int seconds2 = 0, minutes2 = 0, hours2 = 0;
612 if (duration == 0)
613 return rb_make_duration_string (elapsed);
615 if (duration > 0) {
616 hours2 = duration / (60 * 60);
617 minutes2 = (duration - (hours2 * 60 * 60)) / 60;
618 seconds2 = duration % 60;
621 if (elapsed > 0) {
622 hours = elapsed / (60 * 60);
623 minutes = (elapsed - (hours * 60 * 60)) / 60;
624 seconds = elapsed % 60;
627 if (show_remaining) {
628 int remaining = duration - elapsed;
629 int remaining_hours = remaining / (60 * 60);
630 int remaining_minutes = (remaining - (remaining_hours * 60 * 60)) / 60;
631 /* remaining could conceivably be negative. This would
632 * be a bug, but the elapsed time will display right
633 * with the abs(). */
634 int remaining_seconds = abs (remaining % 60);
635 if (hours2 == 0)
636 return g_strdup_printf (_("%d:%02d of %d:%02d remaining"),
637 remaining_minutes, remaining_seconds,
638 minutes2, seconds2);
639 else
640 return g_strdup_printf (_("%d:%02d:%02d of %d:%02d:%02d remaining"),
641 remaining_hours, remaining_minutes, remaining_seconds,
642 hours2, minutes2, seconds2);
643 } else {
644 if (hours == 0 && hours2 == 0)
645 return g_strdup_printf (_("%d:%02d of %d:%02d"),
646 minutes, seconds,
647 minutes2, seconds2);
648 else
649 return g_strdup_printf (_("%d:%02d:%02d of %d:%02d:%02d"),
650 hours, minutes, seconds,
651 hours2, minutes2, seconds2);
655 gboolean
656 rb_string_list_equal (GList *a, GList *b)
658 GList *sorted_a_keys;
659 GList *sorted_b_keys;
660 GList *a_ptr, *b_ptr;
661 gboolean ret = TRUE;
663 if (a == b)
664 return TRUE;
666 if (g_list_length (a) != g_list_length (b))
667 return FALSE;
669 for (sorted_a_keys = NULL; a; a = a->next) {
670 sorted_a_keys = g_list_prepend (sorted_a_keys,
671 g_utf8_collate_key (a->data, -1));
673 for (sorted_b_keys = NULL; b; b = b->next) {
674 sorted_b_keys = g_list_prepend (sorted_b_keys,
675 g_utf8_collate_key (b->data, -1));
677 sorted_a_keys = g_list_sort (sorted_a_keys, (GCompareFunc) strcmp);
678 sorted_b_keys = g_list_sort (sorted_b_keys, (GCompareFunc) strcmp);
680 for (a_ptr = sorted_a_keys, b_ptr = sorted_b_keys;
681 a_ptr && b_ptr; a_ptr = a_ptr->next, b_ptr = b_ptr->next) {
682 if (strcmp (a_ptr->data, b_ptr->data)) {
683 ret = FALSE;
684 break;
687 g_list_foreach (sorted_a_keys, (GFunc) g_free, NULL);
688 g_list_foreach (sorted_b_keys, (GFunc) g_free, NULL);
689 g_list_free (sorted_a_keys);
690 g_list_free (sorted_b_keys);
691 return ret;
694 static void
695 list_copy_cb (const char *s, GList **list)
697 *list = g_list_prepend (*list, g_strdup (s));
700 GList *
701 rb_string_list_copy (GList *list)
703 GList *copy = NULL;
705 if (list == NULL)
706 return NULL;
708 g_list_foreach (list, (GFunc)list_copy_cb, &copy);
709 copy = g_list_reverse (copy);
711 return copy;
714 void
715 rb_list_deep_free (GList *list)
717 g_list_foreach (list, (GFunc)g_free, NULL);
718 g_list_free (list);
722 static void
723 collate_keys_cb (gpointer key, gpointer value, GList **list)
725 *list = g_list_prepend (*list, key);
728 static void
729 collate_values_cb (gpointer key, gpointer value, GList **list)
731 *list = g_list_prepend (*list, value);
734 GList*
735 rb_collate_hash_table_keys (GHashTable *table)
737 GList *list = NULL;
739 g_hash_table_foreach (table, (GHFunc)collate_keys_cb, &list);
740 list = g_list_reverse (list);
742 return list;
745 GList*
746 rb_collate_hash_table_values (GHashTable *table)
748 GList *list = NULL;
750 g_hash_table_foreach (table, (GHFunc)collate_values_cb, &list);
751 list = g_list_reverse (list);
753 return list;
757 * hacked up version of gnome_vfs_uri_list_parse,
758 * that it doesn't strip #s and and returns strings.
761 GList *
762 rb_uri_list_parse (const char *uri_list)
764 const gchar *p, *q;
765 gchar *retval;
766 GList *result = NULL;
768 g_return_val_if_fail (uri_list != NULL, NULL);
770 p = uri_list;
772 while (p != NULL) {
773 while (g_ascii_isspace (*p))
774 p++;
776 q = p;
777 while ((*q != '\0')
778 && (*q != '\n')
779 && (*q != '\r'))
780 q++;
782 if (q > p) {
783 q--;
784 while (q > p
785 && g_ascii_isspace (*q))
786 q--;
788 retval = g_malloc (q - p + 2);
789 strncpy (retval, p, q - p + 1);
790 retval[q - p + 1] = '\0';
792 if (retval != NULL)
793 result = g_list_prepend (result, retval);
795 p = strchr (p, '\n');
796 if (p != NULL)
797 p++;
800 return g_list_reverse (result);
803 const gchar*
804 rb_mime_get_friendly_name (const gchar *mime_type)
806 const gchar *name = NULL;
808 if (name == NULL && mime_type)
809 name = gnome_vfs_mime_get_description (mime_type);
810 if (name == NULL)
811 name = _("Unknown");
813 return name;
816 gboolean
817 rb_signal_accumulator_object_handled (GSignalInvocationHint *hint,
818 GValue *return_accu,
819 const GValue *handler_return,
820 gpointer dummy)
822 if (handler_return == NULL ||
823 !G_VALUE_HOLDS_OBJECT (handler_return) ||
824 g_value_get_object (handler_return) == NULL)
825 return TRUE;
827 g_value_unset (return_accu);
828 g_value_init (return_accu, G_VALUE_TYPE (handler_return));
829 g_value_copy (handler_return, return_accu);
831 return FALSE;
834 void
835 rb_value_array_append_data (GValueArray *array, GType type, ...)
837 GValue val = {0,};
838 va_list va;
839 gchar *err = NULL;
841 va_start (va, type);
843 g_value_init (&val, type);
844 G_VALUE_COLLECT (&val, va, 0, &err);
845 g_value_array_append (array, &val);
846 g_value_unset (&val);
848 if (err)
849 rb_debug ("unable to collect GValue: %s", err);
851 va_end (va);
854 void
855 rb_value_free (GValue *val)
857 g_value_unset (val);
858 g_free (val);