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)
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.
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>
36 static GPrivate
* private_is_primary_thread
;
39 rb_true_function (gpointer dummy
)
45 rb_false_function (gpointer dummy
)
51 rb_null_function (gpointer dummy
)
57 rb_copy_function (gpointer data
)
64 rb_gvalue_compare (GValue
*a
, GValue
*b
)
67 const char *stra
, *strb
;
69 if (G_VALUE_TYPE (a
) != G_VALUE_TYPE (b
))
72 switch (G_VALUE_TYPE (a
))
75 if (g_value_get_int (a
) < g_value_get_int (b
))
77 else if (g_value_get_int (a
) == g_value_get_int (b
))
83 if (g_value_get_char (a
) < g_value_get_char (b
))
85 else if (g_value_get_char (a
) == g_value_get_char (b
))
91 if (g_value_get_uchar (a
) < g_value_get_uchar (b
))
93 else if (g_value_get_uchar (a
) == g_value_get_uchar (b
))
99 if (g_value_get_int (a
) < g_value_get_int (b
))
101 else if (g_value_get_int (a
) == g_value_get_int (b
))
107 if (g_value_get_uint (a
) < g_value_get_uint (b
))
109 else if (g_value_get_uint (a
) == g_value_get_uint (b
))
115 if (g_value_get_long (a
) < g_value_get_long (b
))
117 else if (g_value_get_long (a
) == g_value_get_long (b
))
123 if (g_value_get_ulong (a
) < g_value_get_ulong (b
))
125 else if (g_value_get_ulong (a
) == g_value_get_ulong (b
))
131 if (g_value_get_int64 (a
) < g_value_get_int64 (b
))
133 else if (g_value_get_int64 (a
) == g_value_get_int64 (b
))
139 if (g_value_get_uint64 (a
) < g_value_get_uint64 (b
))
141 else if (g_value_get_uint64 (a
) == g_value_get_uint64 (b
))
147 /* this is somewhat bogus. */
148 if (g_value_get_enum (a
) < g_value_get_enum (b
))
150 else if (g_value_get_enum (a
) == g_value_get_enum (b
))
156 /* this is even more bogus. */
157 if (g_value_get_flags (a
) < g_value_get_flags (b
))
159 else if (g_value_get_flags (a
) == g_value_get_flags (b
))
165 if (g_value_get_float (a
) < g_value_get_float (b
))
167 else if (g_value_get_float (a
) == g_value_get_float (b
))
173 if (g_value_get_double (a
) < g_value_get_double (b
))
175 else if (g_value_get_double (a
) == g_value_get_double (b
))
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
);
188 retval
= (g_value_get_pointer (a
) != g_value_get_pointer (b
));
191 retval
= (g_value_get_boxed (a
) != g_value_get_boxed (b
));
194 retval
= (g_value_get_object (a
) != g_value_get_object (b
));
197 g_assert_not_reached ();
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
212 return a
->tv_usec
> b
->tv_usec
? 1 : -1;
213 else if (a
->tv_sec
> b
->tv_sec
)
219 /* Taken from totem/video-utils.c CVS HEAD 2004-04-22 */
221 totem_pixbuf_mirror (GdkPixbuf
*pixbuf
)
223 int i
, j
, rowstride
, offset
, right
;
225 int width
, height
, size
;
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
))
241 right
= i
+ (((width
- 1) * sizeof(guint32
)) - j
);
246 memcpy (&tmp
, pixels
+ offset
, sizeof(guint32
));
247 memcpy (pixels
+ offset
, pixels
+ right
,
249 memcpy (pixels
+ right
, &tmp
, sizeof(guint32
));
256 /* Same as gtk_image_new_from_stock except that it mirrors the icons for RTL
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
);
271 image
= gtk_image_new ();
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
);
287 totem_pixbuf_mirror (mirror
);
288 gtk_image_set_from_pixbuf (GTK_IMAGE (image
), mirror
);
289 gdk_pixbuf_unref (mirror
);
298 rb_gtk_action_popup_menu (GtkUIManager
*uimanager
, const char *path
)
302 menu
= gtk_ui_manager_get_widget (uimanager
, path
);
304 g_warning ("Couldn't get menu widget for %s", path
);
306 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, 3,
307 gtk_get_current_event_time ());
312 get_mount_points (void)
314 GnomeVFSVolumeMonitor
*monitor
;
317 GList
*mount_points
= NULL
;
319 monitor
= gnome_vfs_get_volume_monitor ();
320 /* FIXME: should also get the list of connected drivers (network
323 volumes
= gnome_vfs_volume_monitor_get_mounted_volumes (monitor
);
325 for (it
= volumes
; it
!= NULL
; it
= it
->next
) {
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
);
343 rb_uri_get_mount_point (const char *uri
)
345 GList
*mount_points
= get_mount_points ();
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
);
364 rb_uri_is_mounted (const char *uri
)
366 GList
*mount_points
= get_mount_points ();
368 gboolean found
= FALSE
;
370 if ((uri
== NULL
) || (*uri
== '\0')) {
374 for (it
= mount_points
; it
!= NULL
; it
= it
->next
) {
375 if (strcmp (it
->data
, uri
) == 0) {
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);
391 rb_is_main_thread (void)
393 if (g_thread_supported()) {
394 return GPOINTER_TO_UINT(g_private_get (private_is_primary_thread
)) == 1;
401 purge_useless_threads (gpointer data
)
403 g_thread_pool_stop_unused_threads ();
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..
418 /* purge useless thread-pool threads occasionally */
419 g_timeout_add (30 * 1000, purge_useless_threads
, NULL
);
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
;
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 */
444 switch (g_unichar_type (*cur_read
)) {
445 case G_UNICODE_UNASSIGNED
:
446 rb_debug ("unassigned unicode character type found");
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 */
458 /* end current word if it isn't ended yet */
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
:
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
;
491 if (cur_write
!= unicode
) {/* first insert has been done above */
492 words
= g_slist_prepend (words
, cur_write
);
500 g_warning ("unknown unicode character type found");
510 ret
= g_new (gchar
*, wordcount
+ 1);
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
);
525 rb_search_fold (const char *original
)
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
:
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
);
571 case G_UNICODE_UNASSIGNED
:
572 rb_debug ("unassigned unicode character type found");
577 g_string_append_unichar (string
, *cur
);
583 return g_string_free (string
, FALSE
);
587 rb_make_duration_string (guint duration
)
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"));
599 str
= g_strdup_printf (_("%d:%02d"), minutes
, seconds
);
601 str
= g_strdup_printf (_("%d:%02d:%02d"), hours
, minutes
, seconds
);
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;
613 return rb_make_duration_string (elapsed
);
616 hours2
= duration
/ (60 * 60);
617 minutes2
= (duration
- (hours2
* 60 * 60)) / 60;
618 seconds2
= duration
% 60;
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
634 int remaining_seconds
= abs (remaining
% 60);
636 return g_strdup_printf (_("%d:%02d of %d:%02d remaining"),
637 remaining_minutes
, remaining_seconds
,
640 return g_strdup_printf (_("%d:%02d:%02d of %d:%02d:%02d remaining"),
641 remaining_hours
, remaining_minutes
, remaining_seconds
,
642 hours2
, minutes2
, seconds2
);
644 if (hours
== 0 && hours2
== 0)
645 return g_strdup_printf (_("%d:%02d of %d:%02d"),
649 return g_strdup_printf (_("%d:%02d:%02d of %d:%02d:%02d"),
650 hours
, minutes
, seconds
,
651 hours2
, minutes2
, seconds2
);
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
;
666 if (g_list_length (a
) != g_list_length (b
))
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
)) {
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
);
695 list_copy_cb (const char *s
, GList
**list
)
697 *list
= g_list_prepend (*list
, g_strdup (s
));
701 rb_string_list_copy (GList
*list
)
708 g_list_foreach (list
, (GFunc
)list_copy_cb
, ©
);
709 copy
= g_list_reverse (copy
);
715 rb_list_deep_free (GList
*list
)
717 g_list_foreach (list
, (GFunc
)g_free
, NULL
);
723 collate_keys_cb (gpointer key
, gpointer value
, GList
**list
)
725 *list
= g_list_prepend (*list
, key
);
729 collate_values_cb (gpointer key
, gpointer value
, GList
**list
)
731 *list
= g_list_prepend (*list
, value
);
735 rb_collate_hash_table_keys (GHashTable
*table
)
739 g_hash_table_foreach (table
, (GHFunc
)collate_keys_cb
, &list
);
740 list
= g_list_reverse (list
);
746 rb_collate_hash_table_values (GHashTable
*table
)
750 g_hash_table_foreach (table
, (GHFunc
)collate_values_cb
, &list
);
751 list
= g_list_reverse (list
);
757 * hacked up version of gnome_vfs_uri_list_parse,
758 * that it doesn't strip #s and and returns strings.
762 rb_uri_list_parse (const char *uri_list
)
766 GList
*result
= NULL
;
768 g_return_val_if_fail (uri_list
!= NULL
, NULL
);
773 while (g_ascii_isspace (*p
))
785 && g_ascii_isspace (*q
))
788 retval
= g_malloc (q
- p
+ 2);
789 strncpy (retval
, p
, q
- p
+ 1);
790 retval
[q
- p
+ 1] = '\0';
793 result
= g_list_prepend (result
, retval
);
795 p
= strchr (p
, '\n');
800 return g_list_reverse (result
);
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
);
817 rb_signal_accumulator_object_handled (GSignalInvocationHint
*hint
,
819 const GValue
*handler_return
,
822 if (handler_return
== NULL
||
823 !G_VALUE_HOLDS_OBJECT (handler_return
) ||
824 g_value_get_object (handler_return
) == NULL
)
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
);
835 rb_value_array_append_data (GValueArray
*array
, GType 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
);
849 rb_debug ("unable to collect GValue: %s", err
);
855 rb_value_free (GValue
*val
)