Updated Macedonian Translation <arangela@cvs.gnome.org>
[rhythmbox.git] / lib / rb-util.c
blob14591194fd141824f3b1d514427b9b48d79bd5ee
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include "rb-util.h"
23 #include <gtk/gtk.h>
24 #include <string.h>
25 #include <libgnome/gnome-i18n.h>
26 #include <libgnomevfs/gnome-vfs.h>
27 #include "rb-debug.h"
29 static GPrivate * private_is_primary_thread;
31 gboolean
32 rb_true_function (gpointer dummy)
34 return TRUE;
37 gboolean
38 rb_false_function (gpointer dummy)
40 return FALSE;
43 gpointer
44 rb_null_function (gpointer dummy)
46 return NULL;
49 int
50 rb_gvalue_compare (GValue *a, GValue *b)
52 int retval;
53 const char *stra, *strb;
55 switch (G_VALUE_TYPE (a))
57 case G_TYPE_BOOLEAN:
58 if (g_value_get_int (a) < g_value_get_int (b))
59 retval = -1;
60 else if (g_value_get_int (a) == g_value_get_int (b))
61 retval = 0;
62 else
63 retval = 1;
64 break;
65 case G_TYPE_CHAR:
66 if (g_value_get_char (a) < g_value_get_char (b))
67 retval = -1;
68 else if (g_value_get_char (a) == g_value_get_char (b))
69 retval = 0;
70 else
71 retval = 1;
72 break;
73 case G_TYPE_UCHAR:
74 if (g_value_get_uchar (a) < g_value_get_uchar (b))
75 retval = -1;
76 else if (g_value_get_uchar (a) == g_value_get_uchar (b))
77 retval = 0;
78 else
79 retval = 1;
80 break;
81 case G_TYPE_INT:
82 if (g_value_get_int (a) < g_value_get_int (b))
83 retval = -1;
84 else if (g_value_get_int (a) == g_value_get_int (b))
85 retval = 0;
86 else
87 retval = 1;
88 break;
89 case G_TYPE_UINT:
90 if (g_value_get_uint (a) < g_value_get_uint (b))
91 retval = -1;
92 else if (g_value_get_uint (a) == g_value_get_uint (b))
93 retval = 0;
94 else
95 retval = 1;
96 break;
97 case G_TYPE_LONG:
98 if (g_value_get_long (a) < g_value_get_long (b))
99 retval = -1;
100 else if (g_value_get_long (a) == g_value_get_long (b))
101 retval = 0;
102 else
103 retval = 1;
104 break;
105 case G_TYPE_ULONG:
106 if (g_value_get_ulong (a) < g_value_get_ulong (b))
107 retval = -1;
108 else if (g_value_get_ulong (a) == g_value_get_ulong (b))
109 retval = 0;
110 else
111 retval = 1;
112 break;
113 case G_TYPE_INT64:
114 if (g_value_get_int64 (a) < g_value_get_int64 (b))
115 retval = -1;
116 else if (g_value_get_int64 (a) == g_value_get_int64 (b))
117 retval = 0;
118 else
119 retval = 1;
120 break;
121 case G_TYPE_UINT64:
122 if (g_value_get_uint64 (a) < g_value_get_uint64 (b))
123 retval = -1;
124 else if (g_value_get_uint64 (a) == g_value_get_uint64 (b))
125 retval = 0;
126 else
127 retval = 1;
128 break;
129 case G_TYPE_ENUM:
130 /* this is somewhat bogus. */
131 if (g_value_get_enum (a) < g_value_get_enum (b))
132 retval = -1;
133 else if (g_value_get_enum (a) == g_value_get_enum (b))
134 retval = 0;
135 else
136 retval = 1;
137 break;
138 case G_TYPE_FLAGS:
139 /* this is even more bogus. */
140 if (g_value_get_flags (a) < g_value_get_flags (b))
141 retval = -1;
142 else if (g_value_get_flags (a) == g_value_get_flags (b))
143 retval = 0;
144 else
145 retval = 1;
146 break;
147 case G_TYPE_FLOAT:
148 if (g_value_get_float (a) < g_value_get_float (b))
149 retval = -1;
150 else if (g_value_get_float (a) == g_value_get_float (b))
151 retval = 0;
152 else
153 retval = 1;
154 break;
155 case G_TYPE_DOUBLE:
156 if (g_value_get_double (a) < g_value_get_double (b))
157 retval = -1;
158 else if (g_value_get_double (a) == g_value_get_double (b))
159 retval = 0;
160 else
161 retval = 1;
162 break;
163 case G_TYPE_STRING:
164 stra = g_value_get_string (a);
165 strb = g_value_get_string (b);
166 if (stra == NULL) stra = "";
167 if (strb == NULL) strb = "";
168 retval = g_utf8_collate (stra, strb);
169 break;
170 case G_TYPE_POINTER:
171 case G_TYPE_BOXED:
172 case G_TYPE_OBJECT:
173 default:
174 g_assert_not_reached ();
175 retval = 0;
176 break;
178 return retval;
182 rb_compare_gtimeval (GTimeVal *a, GTimeVal *b)
184 if (a->tv_sec == b->tv_sec)
185 /* It's quite unlikely that microseconds are equal,
186 * so just ignore that case, we don't need a lot
187 * of precision.
189 return a->tv_usec > b->tv_usec ? 1 : -1;
190 else if (a->tv_sec > b->tv_sec)
191 return 1;
192 else
193 return -1;
196 /* Taken from totem/video-utils.c CVS HEAD 2004-04-22 */
197 static void
198 totem_pixbuf_mirror (GdkPixbuf *pixbuf)
200 int i, j, rowstride, offset, right;
201 guchar *pixels;
202 int width, height, size;
203 guint32 tmp;
205 pixels = gdk_pixbuf_get_pixels (pixbuf);
206 g_return_if_fail (pixels != NULL);
208 width = gdk_pixbuf_get_width (pixbuf);
209 height = gdk_pixbuf_get_height (pixbuf);
210 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
211 size = height * width * sizeof (guint32);
213 for (i = 0; i < size; i += rowstride)
215 for (j = 0; j < rowstride; j += sizeof(guint32))
217 offset = i + j;
218 right = i + (((width - 1) * sizeof(guint32)) - j);
220 if (right <= offset)
221 break;
223 memcpy (&tmp, pixels + offset, sizeof(guint32));
224 memcpy (pixels + offset, pixels + right,
225 sizeof(guint32));
226 memcpy (pixels + right, &tmp, sizeof(guint32));
233 /* Same as gtk_image_new_from_stock except that it mirrors the icons for RTL
234 * languages
236 GtkWidget *
237 rb_image_new_from_stock (const gchar *stock_id, GtkIconSize size)
240 if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR) {
241 return gtk_image_new_from_stock (stock_id, size);
242 } else {
244 GtkWidget *image;
245 GdkPixbuf *pixbuf;
246 GdkPixbuf *mirror;
248 image = gtk_image_new ();
250 if (image == NULL) {
251 return NULL;
254 pixbuf = gtk_widget_render_icon (image, stock_id, size, NULL);
255 g_assert (pixbuf != NULL);
258 mirror = gdk_pixbuf_copy (pixbuf);
259 gdk_pixbuf_unref (pixbuf);
261 if (!mirror)
262 return NULL;
264 totem_pixbuf_mirror (mirror);
265 gtk_image_set_from_pixbuf (GTK_IMAGE (image), mirror);
266 gdk_pixbuf_unref (mirror);
268 return image;
271 return NULL;
274 void
275 rb_gtk_action_popup_menu (GtkUIManager *uimanager, const char *path)
277 GtkWidget *menu;
279 menu = gtk_ui_manager_get_widget (uimanager, path);
280 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3,
281 gtk_get_current_event_time ());
284 static GList *
285 get_mount_points (void)
287 GnomeVFSVolumeMonitor *monitor;
288 GList *volumes;
289 GList *it;
290 GList *mount_points = NULL;
292 monitor = gnome_vfs_get_volume_monitor ();
293 /* FIXME: should also get the list of connected drivers (network
294 * shares I assume)
296 volumes = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
298 for (it = volumes; it != NULL; it = it->next) {
299 gchar *uri;
300 GnomeVFSVolume *volume;
302 volume = GNOME_VFS_VOLUME (it->data);
303 uri = gnome_vfs_volume_get_activation_uri (volume);
304 g_assert (uri != NULL);
305 mount_points = g_list_prepend (mount_points, uri);
308 g_list_foreach (volumes, (GFunc)gnome_vfs_volume_ref, NULL);
309 g_list_free (volumes);
311 return mount_points;
315 gchar *
316 rb_uri_get_mount_point (const char *uri)
318 GList *mount_points = get_mount_points ();
319 GList *it;
320 gchar *mount_point = NULL;
322 for (it = mount_points; it != NULL; it = it->next) {
323 if (g_str_has_prefix (uri, it->data)) {
324 if ((mount_point == NULL) || (strlen (mount_point) < strlen (it->data))) {
325 g_free (mount_point);
326 mount_point = g_strdup (it->data);
330 g_list_foreach (mount_points, (GFunc)g_free, NULL);
331 g_list_free (mount_points);
333 return mount_point;
336 gboolean
337 rb_uri_is_mounted (const char *uri)
339 GList *mount_points = get_mount_points ();
340 GList *it;
341 gboolean found = FALSE;
343 if ((uri == NULL) || (*uri == '\0')) {
344 return TRUE;
347 for (it = mount_points; it != NULL; it = it->next) {
348 if (strcmp (it->data, uri) == 0) {
349 found = TRUE;
350 break;
353 g_list_foreach (mount_points, (GFunc)g_free, NULL);
354 g_list_free (mount_points);
356 /* if (found == FALSE) {
357 g_print ("%s not mounted\n", uri);
360 return found;
363 gboolean
364 rb_is_main_thread (void)
366 if (g_thread_supported()) {
367 return GPOINTER_TO_UINT(g_private_get (private_is_primary_thread)) == 1;
368 } else {
369 return TRUE;
374 void
375 rb_threads_init (void)
377 private_is_primary_thread = g_private_new (NULL);
378 g_private_set (private_is_primary_thread, GUINT_TO_POINTER (1));
380 /* not really necessary, but in case it does something besides
381 * set up lock functions some day..
383 gdk_threads_init ();
386 gchar **
387 rb_string_split_words (const gchar *string)
389 /*return g_slist_prepend (NULL, g_strdup (string));*/
391 GSList *words, *current;
392 gunichar *unicode, *cur_write, *cur_read;
393 gchar **ret;
394 gint i, wordcount = 1;
395 gboolean new_word = TRUE;
397 g_return_val_if_fail (string != NULL, NULL);
399 cur_write = cur_read = unicode = g_utf8_to_ucs4_fast (string, -1, NULL);
401 /* we may fail here, we expect valid utf-8 */
402 g_return_val_if_fail (unicode != NULL, NULL);
404 words = g_slist_prepend (NULL, unicode);
406 /* now normalize this text */
407 while (*cur_read) {
408 switch (g_unichar_type (*cur_read)) {
409 case G_UNICODE_UNASSIGNED:
410 g_warning ("unassigned unicode character type found");
411 /* fall through */
412 case G_UNICODE_CONTROL:
413 case G_UNICODE_FORMAT:
414 case G_UNICODE_PRIVATE_USE:
416 case G_UNICODE_SURROGATE:
417 case G_UNICODE_LINE_SEPARATOR:
418 case G_UNICODE_PARAGRAPH_SEPARATOR:
419 case G_UNICODE_SPACE_SEPARATOR:
420 /* remove these and start a new word */
421 if (!new_word) {
422 /* end current word if it isn't ended yet */
423 *cur_write++ = 0;
424 new_word = TRUE;
427 break;
428 case G_UNICODE_COMBINING_MARK:
429 case G_UNICODE_ENCLOSING_MARK:
430 case G_UNICODE_NON_SPACING_MARK:
431 case G_UNICODE_CONNECT_PUNCTUATION:
432 case G_UNICODE_DASH_PUNCTUATION:
433 case G_UNICODE_CLOSE_PUNCTUATION:
434 case G_UNICODE_FINAL_PUNCTUATION:
435 case G_UNICODE_INITIAL_PUNCTUATION:
436 case G_UNICODE_OTHER_PUNCTUATION:
437 case G_UNICODE_OPEN_PUNCTUATION:
438 /* remove these */
439 /*break;*/
440 case G_UNICODE_LOWERCASE_LETTER:
441 case G_UNICODE_MODIFIER_LETTER:
442 case G_UNICODE_OTHER_LETTER:
443 case G_UNICODE_TITLECASE_LETTER:
444 case G_UNICODE_UPPERCASE_LETTER:
445 case G_UNICODE_DECIMAL_NUMBER:
446 case G_UNICODE_LETTER_NUMBER:
447 case G_UNICODE_OTHER_NUMBER:
448 case G_UNICODE_CURRENCY_SYMBOL:
449 case G_UNICODE_MODIFIER_SYMBOL:
450 case G_UNICODE_MATH_SYMBOL:
451 case G_UNICODE_OTHER_SYMBOL:
452 /* keep these unchanged */
453 *cur_write = *cur_read;
454 if (new_word) {
455 if (cur_write != unicode) {/* first insert has been done above */
456 words = g_slist_prepend (words, cur_write);
457 wordcount++;
459 new_word = FALSE;
461 cur_write++;
462 break;
463 default:
464 g_warning ("unknown unicode character type found");
465 break;
467 cur_read++;
470 if (!new_word) {
471 *cur_write++ = 0;
474 ret = g_new (gchar *, wordcount + 1);
475 current = words;
476 for (i = wordcount - 1; i >= 0; i--) {
477 ret[i] = g_ucs4_to_utf8 (current->data, -1, NULL, NULL, NULL);
478 current = g_slist_next (current);
480 ret[wordcount] = NULL;
482 g_slist_free (words);
483 g_free (unicode);
485 return ret;
488 gchar*
489 rb_search_fold (const char *original)
491 GString *string;
492 gunichar *unicode, *cur;
494 g_return_val_if_fail (original != NULL, NULL);
496 /* old behaviour is equivalent to: return g_utf8_casefold (original, -1); */
498 string = g_string_new (NULL);
499 unicode = g_utf8_to_ucs4_fast (original, -1, NULL);
501 for (cur = unicode; *cur != 0; cur++) {
502 switch (g_unichar_type (*cur)) {
503 case G_UNICODE_COMBINING_MARK:
504 case G_UNICODE_ENCLOSING_MARK:
505 case G_UNICODE_NON_SPACING_MARK:
506 case G_UNICODE_CONNECT_PUNCTUATION:
507 case G_UNICODE_DASH_PUNCTUATION:
508 case G_UNICODE_CLOSE_PUNCTUATION:
509 case G_UNICODE_FINAL_PUNCTUATION:
510 case G_UNICODE_INITIAL_PUNCTUATION:
511 case G_UNICODE_OTHER_PUNCTUATION:
512 case G_UNICODE_OPEN_PUNCTUATION:
513 /* remove these */
514 break;
516 case G_UNICODE_LOWERCASE_LETTER:
517 case G_UNICODE_MODIFIER_LETTER:
518 case G_UNICODE_OTHER_LETTER:
519 case G_UNICODE_TITLECASE_LETTER:
520 case G_UNICODE_UPPERCASE_LETTER:
521 /* convert to lower case */
522 *cur = g_unichar_tolower (*cur);
523 /* ... and fall through */\
524 case G_UNICODE_DECIMAL_NUMBER:
525 case G_UNICODE_LETTER_NUMBER:
526 case G_UNICODE_OTHER_NUMBER:
527 /* should be keep symbols? */
528 case G_UNICODE_CURRENCY_SYMBOL:
529 case G_UNICODE_MODIFIER_SYMBOL:
530 case G_UNICODE_MATH_SYMBOL:
531 case G_UNICODE_OTHER_SYMBOL:
532 g_string_append_unichar (string, *cur);
533 break;
535 case G_UNICODE_UNASSIGNED:
536 g_warning ("unassigned unicode character type found");
537 /* fall through */
539 default:
540 /* leave these in */
541 g_string_append_unichar (string, *cur);
545 g_free (unicode);
547 return g_string_free (string, FALSE);
550 char *
551 rb_make_duration_string (guint duration)
553 char *str;
554 int hours, minutes, seconds;
556 hours = duration / (60 * 60);
557 minutes = (duration - (hours * 60 * 60)) / 60;
558 seconds = duration % 60;
560 if (hours == 0 && minutes == 0 && seconds == 0)
561 str = g_strdup (_("Unknown"));
562 else if (hours == 0)
563 str = g_strdup_printf (_("%d:%02d"), minutes, seconds);
564 else
565 str = g_strdup_printf (_("%d:%02d:%02d"), hours, minutes, seconds);
567 return str;
570 gboolean
571 rb_string_list_equal (GList *a, GList *b)
573 GList *sorted_a_keys;
574 GList *sorted_b_keys;
575 GList *a_ptr, *b_ptr;
576 gboolean ret = TRUE;
578 if (a == b)
579 return TRUE;
581 if (g_list_length (a) != g_list_length (b))
582 return FALSE;
584 for (sorted_a_keys = NULL; a; a = a->next) {
585 sorted_a_keys = g_list_prepend (sorted_a_keys,
586 g_utf8_collate_key (a->data, -1));
588 for (sorted_b_keys = NULL; b; b = b->next) {
589 sorted_b_keys = g_list_prepend (sorted_b_keys,
590 g_utf8_collate_key (b->data, -1));
592 sorted_a_keys = g_list_sort (sorted_a_keys, (GCompareFunc) strcmp);
593 sorted_b_keys = g_list_sort (sorted_b_keys, (GCompareFunc) strcmp);
595 for (a_ptr = sorted_a_keys, b_ptr = sorted_b_keys;
596 a_ptr && b_ptr; a_ptr = a_ptr->next, b_ptr = b_ptr->next) {
597 if (strcmp (a_ptr->data, b_ptr->data)) {
598 ret = FALSE;
599 break;
602 g_list_foreach (sorted_a_keys, (GFunc) g_free, NULL);
603 g_list_foreach (sorted_b_keys, (GFunc) g_free, NULL);
604 g_list_free (sorted_a_keys);
605 g_list_free (sorted_b_keys);
606 return ret;
609 static void
610 list_copy_cb (const char *s, GList **list)
612 *list = g_list_prepend (*list, g_strdup (s));
615 GList *
616 rb_string_list_copy (GList *list)
618 GList *copy = NULL;
620 if (list == NULL)
621 return NULL;
623 g_list_foreach (list, (GFunc)list_copy_cb, &copy);
624 copy = g_list_reverse (copy);
626 return copy;
629 void
630 rb_list_deep_free (GList *list)
632 g_list_foreach (list, (GFunc)g_free, NULL);
633 g_list_free (list);
637 static void
638 collate_keys_cb (gpointer key, gpointer value, GList **list)
640 *list = g_list_prepend (*list, key);
643 static void
644 collate_values_cb (gpointer key, gpointer value, GList **list)
646 *list = g_list_prepend (*list, value);
649 GList*
650 rb_collate_hash_table_keys (GHashTable *table)
652 GList *list = NULL;
654 g_hash_table_foreach (table, (GHFunc)collate_keys_cb, &list);
655 list = g_list_reverse (list);
657 return list;
660 GList*
661 rb_collate_hash_table_values (GHashTable *table)
663 GList *list = NULL;
665 g_hash_table_foreach (table, (GHFunc)collate_values_cb, &list);
666 list = g_list_reverse (list);
668 return list;