Add initial right mouse menu to DataView.
[gmpc.git] / src / Tools / misc.c
blob44aad9031f8ec978119ad925413251f083640e3c
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <gtk/gtk.h>
21 #include <string.h>
23 #include <config.h>
24 #include "main.h"
25 #include <libmpd/libmpd-internal.h>
26 #include "misc.h"
27 #ifndef __USE_BSD
28 #define __USE_BSD
29 #endif
30 #include <math.h>
32 #define LOG_DOMAIN "Gmpc.Misc"
33 /**
34 * format time into
35 * Total time: %i days %i hours %i minutes
37 gchar *format_time(unsigned long seconds)
39 gchar *retv = NULL;
40 gchar *string = g_strdup_printf("%s: ", _("Total time"));
41 retv = format_time_real(seconds, string);
42 g_free(string);
43 return retv;
46 gchar *format_time_real(unsigned long seconds, const gchar * data)
48 GString *str = NULL;
49 int days = seconds / 86400;
50 int hours = (seconds % 86400) / 3600;
51 int minutes = (seconds % 3600) / 60;
52 char *ret;
53 if (seconds == 0)
55 return g_strdup("");
57 str = g_string_new(data);
58 if (days != 0)
60 g_string_append_printf(str, "%i %s ", days, ngettext("day", "days", days));
62 if (hours != 0)
64 g_string_append_printf(str, "%i %s ", hours, ngettext("hour", "hours", hours));
66 if (minutes != 0)
68 g_string_append_printf(str, "%i %s ", minutes, ngettext("minute", "minutes", minutes));
70 if((seconds%60) != 0)
72 g_string_append_printf(str, "%lu %s ", (seconds%60), ngettext("second", "seconds", (seconds%60)));
75 ret = str->str;
76 g_string_free(str, FALSE);
77 return ret;
79 gchar *format_time_real_newline(unsigned long seconds, const gchar * data)
81 GString *str = NULL;
82 int days = seconds / 86400;
83 int hours = (seconds % 86400) / 3600;
84 int minutes = (seconds % 3600) / 60;
85 int set = 0;
86 char *ret;
87 if (seconds == 0)
89 return g_strdup("");
91 str = g_string_new(data);
92 if (days != 0)
94 if(set != 0) {
95 g_string_append_c(str, '\n');
97 g_string_append_printf(str, "%i %s ", days, ngettext("day", "days", days));
98 set = 1;
100 if (hours != 0)
102 if(set != 0) {
103 g_string_append_c(str, '\n');
105 g_string_append_printf(str, "%i %s ", hours, ngettext("hour", "hours", hours));
106 set = 1;
108 if (minutes != 0)
110 if(set != 0) {
111 g_string_append_c(str, '\n');
113 g_string_append_printf(str, "%i %s ", minutes, ngettext("minute", "minutes", minutes));
114 set = 1;
116 if((seconds%60) != 0)
118 if(set != 0) {
119 g_string_append_c(str, '\n');
121 g_string_append_printf(str, "%lu %s ", (seconds%60), ngettext("second", "seconds", (seconds%60)));
122 set = 1;
125 ret = str->str;
126 g_string_free(str, FALSE);
127 return ret;
131 * Wrapper around mpd_song_markup, that escapes the entries for use with pango markup
132 * You still need to make sure "markup" is pango-markup proof
134 void mpd_song_markup_escaped(char *buffer, int size, char *markup, mpd_Song * song2)
136 mpd_Song *song = mpd_newSong();
137 if (song2->title)
139 song->title = g_markup_escape_text(song2->title, -1);
141 if (song2->artist)
143 song->artist = g_markup_escape_text(song2->artist, -1);
145 if (song2->albumartist)
147 song->albumartist = g_markup_escape_text(song2->albumartist, -1);
149 if (song2->album)
151 song->album = g_markup_escape_text(song2->album, -1);
153 if (song2->track)
155 song->track = g_markup_escape_text(song2->track, -1);
157 if (song2->name)
159 song->name = g_markup_escape_text(song2->name, -1);
161 if (song2->date)
163 song->date = g_markup_escape_text(song2->date, -1);
165 if (song2->genre)
167 song->genre = g_markup_escape_text(song2->genre, -1);
169 if (song2->composer)
171 song->composer = g_markup_escape_text(song2->composer, -1);
173 if (song2->disc)
175 song->disc = g_markup_escape_text(song2->disc, -1);
177 if (song2->comment)
179 song->comment = g_markup_escape_text(song2->comment, -1);
181 if (song2->file)
183 song->file = g_markup_escape_text(song2->file, -1);
185 song->id = song2->id;
186 song->pos = song2->pos;
187 song->time = song2->time;
189 mpd_song_markup(buffer, size, markup, song);
190 mpd_freeSong(song);
194 * Code copied from gnome-screenshot
197 void screenshot_add_border(GdkPixbuf * src)
199 GdkPixbuf *pb = src;
200 int x, y, width, height;
201 int pixel;
202 int n_channels = 0;
203 int rowstride = 0;
204 guchar *pixels;
206 if (!pb)
208 return;
211 rowstride = gdk_pixbuf_get_rowstride(pb);
212 n_channels = gdk_pixbuf_get_n_channels(pb);
213 width = gdk_pixbuf_get_width(pb);
214 height = gdk_pixbuf_get_height(pb);
215 pixels = gdk_pixbuf_get_pixels(pb);
217 for (y = 0; y < height; y++)
219 for (x = 0; x < width; x++)
221 if (y == 0 || y == (height - 1) || x == 0 || x == (width - 1))
223 for (pixel = 0; pixel < n_channels; pixel++)
225 pixels[x * n_channels + y * rowstride + pixel] = 0;
233 * @param: The filename or empty, to get dir path.
235 * Function to get the full user of filename for gmpc.
236 * On unix this is ~/.config/gmpc/filename
238 * returns: an allocated string.
240 gchar *gmpc_get_user_path(const gchar * filename)
242 const gchar *homedir = g_get_user_config_dir();
243 gchar *ret = NULL;
245 /* Build the path */
246 ret = g_build_path(G_DIR_SEPARATOR_S, homedir, "gmpc", filename, NULL);
248 return ret;
252 * @param: The filename or empty, to get dir path.
254 * Function to get the full user of filename for gmpc's cover.
255 * On unix this is ~/.cache/gmpc/metadata/filename
257 * returns: an allocated string.
259 gchar *gmpc_get_covers_path(const gchar * filename)
261 const gchar *homedir = g_get_user_cache_dir();
262 gchar *ret = NULL;
264 /* Build the path */
265 ret = g_build_path(G_DIR_SEPARATOR_S, homedir, "gmpc", "metadata", filename, NULL);
266 return ret;
271 * @param: The filename or empty, to get dir path.
273 * Function to get the cache directory
274 * On unix this is ~/.cache/gmpc/filename
276 * returns: an allocated string.
278 gchar *gmpc_get_cache_directory(const gchar * filename)
280 const gchar *homedir = g_get_user_cache_dir();
281 gchar *ret = NULL;
283 /* Build the path */
284 ret = g_build_path(G_DIR_SEPARATOR_S, homedir, "gmpc", filename, NULL);
285 return ret;
289 * Get's the full path to an image,
290 * While this is compile time on linux, windows
291 * needs to determine it run-time.
293 char *gmpc_get_full_image_path(void)
295 gchar *path;
296 const gchar *const *paths = g_get_system_data_dirs();
297 int i;
299 /* First try the compile time path */
300 path = g_build_filename(PIXMAP_PATH, NULL);
301 if (path)
303 if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
305 return path;
307 g_free(path);
308 path = NULL;
311 for (i = 0; paths && paths[i]; i++)
313 path = g_build_filename(paths[i], "gmpc", "icons", NULL);
314 if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
316 return path;
318 g_free(path);
319 path = NULL;
321 if (path == NULL)
323 g_error("Failed to find images");
324 return NULL;
326 return path;
330 * Get the full path to the glade files.
331 * While this is compile time on linux, windows
332 * needs to determine it run-time
334 char *gmpc_get_full_glade_path(const char *filename)
336 gchar *path;
337 const gchar *const *paths = g_get_system_data_dirs();
338 int i;
340 path = g_build_filename(GLADE_PATH, filename, NULL);
341 if (path)
343 if (g_file_test(path, G_FILE_TEST_EXISTS))
345 return path;
347 g_free(path);
349 for (i = 0; paths && paths[i]; i++)
351 path = g_build_filename(paths[i], "gmpc", filename, NULL);
352 if (g_file_test(path, G_FILE_TEST_EXISTS))
354 return path;
356 g_free(path);
357 path = NULL;
359 if (path == NULL)
361 g_error("Failed to locate glade path");
362 return NULL;
364 return path;
367 void open_uri(const gchar * uri)
369 int result;
370 gchar *command;
371 GError *error = NULL;
372 #ifdef WIN32
373 gchar *browser_command =
374 cfg_get_single_value_as_string_with_default(config, "External", "browser-win32", "cmd /c start \"%s\"");
375 #else
376 #ifdef OSX
377 gchar *browser_command = cfg_get_single_value_as_string_with_default(config, "External", "browser-osx", "open \"%s\"");
378 #else
379 gchar *browser_command = cfg_get_single_value_as_string_with_default(config, "External", "browser", "xdg-open \"%s\"");
380 #endif
381 #endif
382 gchar *escaped_uri = g_strescape(uri, "");
383 command = g_strdup_printf(browser_command, escaped_uri);
384 g_free(escaped_uri);
385 result = g_spawn_command_line_async(command, &error);
386 if (error)
389 gchar *str = g_markup_printf_escaped("%s: '%s': %s", _("Failed to execute"), command, error->message);
390 playlist3_show_error_message(str, ERROR_WARNING);
391 g_free(str);
392 g_error_free(error);
393 error = NULL;
395 g_free(browser_command);
396 g_free(command);
400 * Call yelp!
402 void open_help(const char *uri)
403 { int result;
404 gchar *command;
405 GError *error = NULL;
406 command = g_strdup_printf("yelp %s", uri);
407 result = g_spawn_command_line_async(command, &error);
408 if (error)
410 /* Ignore errors for now */
411 g_error_free(error);
412 error = NULL;
414 g_free(command);
418 int *split_version(const char *uri)
420 int *retv = g_malloc0(4 * sizeof(int));
421 char **sp = g_strsplit(uri, ".", 4);
422 int i;
423 for (i = 0; i < 4 && sp[i]; i++)
425 retv[i] = atoi(sp[i]);
427 g_strfreev(sp);
428 return retv;
431 MpdData *misc_sort_mpddata(MpdData * data, GCompareDataFunc func, void *user_data)
433 int j;
434 int i = 0;
435 MpdData_real *node;
436 MpdData_real **nodes;
437 INIT_TIC_TAC();
439 if (data == NULL)
440 return NULL;
442 for (node = (MpdData_real *) mpd_data_get_first(data); node;
443 node = (MpdData_real *) mpd_data_get_next_real((MpdData *) node, FALSE))
444 i++;
445 TEC("Counted items");
447 nodes = g_malloc0(i * sizeof(MpdData_real *));
449 node = (MpdData_real *) mpd_data_get_first(data);
450 for (j = 0; j < i; j++)
452 nodes[j] = node;
453 node = (MpdData_real *) mpd_data_get_next_real((MpdData *) node, FALSE);
455 TEC("Created array");
456 g_qsort_with_data(nodes, i, sizeof(MpdData_real *), func, user_data);
457 TEC("Sorted array");
458 nodes[0]->prev = NULL;
459 nodes[0]->next = NULL;
460 nodes[0]->first = nodes[0];
461 for (j = 1; j < i; j++)
463 nodes[j]->prev = nodes[j - 1];
464 nodes[j]->next = NULL;
465 nodes[j]->prev->next = nodes[j];
466 nodes[j]->first = nodes[0];
468 data = (MpdData *) nodes[0];
469 g_free(nodes);
470 TEC("Recreated linked list");
471 return data;
474 static gint __add_sort(gpointer aa, gpointer bb, gpointer data)
476 MpdData_real *a = *(MpdData_real **) aa;
477 MpdData_real *b = *(MpdData_real **) bb;
478 if (a->type == MPD_DATA_TYPE_DIRECTORY && b->type == MPD_DATA_TYPE_DIRECTORY)
480 if (a->directory == NULL && b->directory != NULL)
481 return -1;
482 else if (b->directory == NULL && a->directory != NULL)
483 return 1;
484 else if (a->directory && b->directory)
486 int val;
487 if (a->directory && b->directory)
489 gchar *sa, *sb;
490 sa = g_utf8_strdown(a->directory, -1);
491 sb = g_utf8_strdown(b->directory, -1);
492 val = g_utf8_collate(sa, sb);
493 g_free(sa);
494 g_free(sb);
495 } else
497 val = (a == NULL) ? ((b == NULL) ? 0 : -1) : 1;
499 return val;
502 if (a->type == MPD_DATA_TYPE_TAG && b->type == MPD_DATA_TYPE_TAG)
504 if (a->tag_type != b->tag_type)
505 return a->tag_type - b->tag_type;
506 if (a->tag == NULL && b->tag != NULL)
507 return -1;
508 else if (b->tag == NULL && a->tag != NULL)
509 return 1;
510 else if (a->tag && b->tag)
512 int val;
513 if (a->tag && b->tag)
515 gchar *sa, *sb;
516 sa = g_utf8_strdown(a->tag, -1);
517 sb = g_utf8_strdown(b->tag, -1);
518 val = g_utf8_collate(sa, sb);
519 g_free(sa);
520 g_free(sb);
521 } else
523 val = (a == NULL) ? ((b == NULL) ? 0 : -1) : 1;
525 return val;
528 if (a->type == MPD_DATA_TYPE_SONG && b->type == MPD_DATA_TYPE_SONG)
530 const char *artista = NULL;
531 const char *artistb = NULL;
532 if(a->song->albumartist) artista = a->song->albumartist;
533 else artista = a->song->artist;
534 if(b->song->albumartist) artistb = b->song->albumartist;
535 else artistb = b->song->artist;
536 /* Artist (prefer albumartist, if not use artist field */
537 if (artista == NULL && artistb != NULL)
538 return -1;
539 else if (artistb == NULL && artista != NULL)
540 return 1;
541 else if (artista && artistb)
543 int compv = g_utf8_collate(artista, artistb);
544 if (compv != 0)
546 return compv;
550 /* Date */
551 if (a->song->date == NULL && b->song->date != NULL)
552 return -1;
553 else if (b->song->date == NULL && a->song->date != NULL)
554 return 1;
555 else if (a->song->date && b->song->date)
557 int compv = atoi(a->song->date) - atoi(b->song->date);
558 if (compv != 0)
559 return compv;
561 /* Album name */
562 if (a->song->album == NULL && b->song->album != NULL)
563 return -1;
564 else if (b->song->album == NULL && a->song->album != NULL)
565 return 1;
566 else if (a->song->album && b->song->album)
568 int compv = g_utf8_collate(a->song->album, b->song->album);
570 if (compv != 0)
572 return compv;
575 if (a->song->disc == NULL && b->song->disc != NULL)
576 return -1;
577 else if (b->song->disc == NULL && a->song->disc != NULL)
578 return 1;
579 else if (a->song->disc && b->song->disc)
581 int compv = g_utf8_collate(a->song->disc, b->song->disc);
582 if (compv != 0)
584 return compv;
587 if (a->song->track == NULL && b->song->track != NULL)
588 return -1;
589 else if (b->song->track == NULL && a->song->track != NULL)
590 return 1;
591 else if (a->song->track && b->song->track)
593 int compv = atoi(a->song->track) - atoi(b->song->track);
594 return compv;
597 return a->type - b->type;
600 MpdData *misc_sort_mpddata_by_album_disc_track(MpdData * data)
602 return misc_sort_mpddata(data, (GCompareDataFunc) __add_sort, NULL);
605 static gint __sort_filename(gpointer aa, gpointer bb, gpointer data)
607 MpdData_real *a = *(MpdData_real **) aa;
608 MpdData_real *b = *(MpdData_real **) bb;
610 if (a->type == MPD_DATA_TYPE_SONG && b->type == MPD_DATA_TYPE_SONG)
612 if (a->song->file && b->song->file)
613 return strcmp(a->song->file, b->song->file);
614 else
616 gchar *chk_a = mpd_song_checksum(a->song);
617 gchar *chk_b = mpd_song_checksum(b->song);
618 int retv = strcmp(chk_a, chk_b);
619 g_free(chk_a);
620 g_free(chk_b);
621 return retv;
623 } else if (a->type == MPD_DATA_TYPE_TAG && b->type == MPD_DATA_TYPE_TAG)
625 if (a->tag_type == b->tag_type)
626 return strcmp(a->tag, b->tag);
628 return a->type - b->type;
631 MpdData *misc_mpddata_remove_duplicate_songs(MpdData * data)
633 MpdData_real *node;
634 if (!data)
635 return NULL;
636 /* sort on file filename, this is our key */
637 node = (MpdData_real *) misc_sort_mpddata(data, (GCompareDataFunc) __sort_filename, NULL);
638 /* loop through it */
639 while (node->next)
641 if (node->type == MPD_DATA_TYPE_SONG && node->next->type == MPD_DATA_TYPE_SONG)
643 if (__sort_filename(&node, &(node->next), NULL) == 0) //strcmp(node->song->file, node->next->song->file) == 0)
645 node = (MpdData_real *) mpd_data_delete_item((MpdData *) node);
646 continue;
648 } else if (node->type == MPD_DATA_TYPE_TAG && node->next->type == MPD_DATA_TYPE_TAG)
650 if (__sort_filename(&(node), &(node->next), NULL) == 0) //strcmp(node->tag, node->next->tag) == 0)
652 node = (MpdData_real *) mpd_data_delete_item((MpdData *) node);
653 continue;
656 node = node->next;
658 return (MpdData *) node->first;
661 gchar **tokenize_string(const gchar * string)
663 gchar **result = NULL; /* the result with tokens */
664 int i = 0; /* position in string */
665 int br = 0; /* number for open ()[]'s */
666 int bpos = 0; /* begin position of the cur. token */
667 int bstop = 0;
668 int tokens = 0;
669 int length = 0;
670 if (string == NULL)
671 return NULL;
672 length = strlen(string);
673 for (i = 0; i <= length; i++)
675 /* check for opening [( */
676 if ((br != 0 || bpos == i) && (string[i] == '(' || string[i] == '[' || string[i] == '{'))
678 if (!br && bpos == i)
679 bpos = i + 1;
680 br++;
682 /* check closing */
683 else if (br && (string[i] == ')' || string[i] == ']' || string[i] == '}'))
685 br--;
686 bstop = i;
687 if (!br && (string[i + 1] == ' ' || string[i + 1] == '\0'))
689 i++;
691 } else
692 bstop = i;
693 /* if multiple spaces at begin of token skip them */
694 if (string[i] == ' ' && !(i - bpos))
695 bpos++;
696 /* if token end or string end add token to list */
697 else if ((string[i] == ' ' && !br) || string[i] == '\0')
699 if ((bstop - bpos) > 0)
701 result = g_realloc(result, (tokens + 2) * sizeof(gchar *));
702 result[tokens] = g_strndup(&string[bpos], bstop - bpos);
703 result[tokens + 1] = NULL;
704 bpos = i + 1;
705 bstop = bpos;
706 tokens++;
711 return result;
714 void misc_header_style_set_process_containers(GtkWidget * container, GtkStyle * old_style, gpointer data)
717 GtkStyle *style = container->style;
718 GList *list = NULL;
719 list = gtk_container_get_children(GTK_CONTAINER(container));
720 if (list)
722 GList *node;
723 for (node = g_list_first(list); node; node = g_list_next(node))
725 gtk_widget_modify_fg((GtkWidget *) node->data, GTK_STATE_NORMAL, &(style->fg[GTK_STATE_SELECTED]));
726 gtk_widget_modify_text((GtkWidget *) node->data, GTK_STATE_NORMAL, &(style->fg[GTK_STATE_SELECTED]));
727 if (GTK_IS_CONTAINER(node->data))
729 misc_header_style_set_process_containers((GtkWidget *) node->data, NULL, NULL);
732 g_list_free(list);
737 gboolean misc_header_expose_event(GtkWidget * widget, cairo_t * ct)
739 /* TODO:
740 int width = widget->allocation.width;
741 int height = widget->allocation.height;
743 gtk_paint_flat_box(widget->style,
744 widget->window,
745 GTK_STATE_SELECTED, GTK_SHADOW_NONE, &(event->area), widget, "cell_odd", 0, 0, width, height);
746 gtk_paint_focus(widget->style, widget->window,
747 GTK_STATE_NORMAL, &(event->area), widget, "button", 0, 0, width, height);
749 printf("test\n");
750 GtkAllocation alloc;
751 GtkStyleContext *context = gtk_widget_get_style_context(widget);
752 gtk_style_context_set_state(context, GTK_STATE_SELECTED);
753 gtk_widget_set_state(GTK_WIDGET(widget), GTK_STATE_SELECTED);
754 gtk_widget_get_allocation(GTK_WIDGET(widget), &alloc);
755 gtk_render_background(context, ct,0,0, alloc.width, alloc.height);
756 return FALSE;
759 gchar *mpd_song_checksum_type(const mpd_Song * song, MetaDataType type)
761 gchar *retv = NULL;
763 if (song)
765 GChecksum *cs = g_checksum_new(G_CHECKSUM_SHA256);
766 switch(type)
768 case META_ARTIST_SIMILAR:
769 case META_ARTIST_TXT:
770 case META_ARTIST_ART:
771 if (song->artist)
772 g_checksum_update(cs, (guchar *) song->artist, -1);
773 break;
774 case META_ALBUM_ART:
775 case META_ALBUM_TXT:
776 case META_BACKDROP_ART:
777 if (song->album)
778 g_checksum_update(cs, (guchar *) song->album, -1);
779 if (song->artist)
780 g_checksum_update(cs, (guchar *) song->artist, -1);
781 break;
782 case META_SONG_TXT:
783 case META_SONG_SIMILAR:
784 case META_SONG_GUITAR_TAB:
785 if (song->artist)
786 g_checksum_update(cs, (guchar *) song->artist, -1);
787 if (song->title)
788 g_checksum_update(cs, (guchar *) song->title, -1);
789 break;
790 case META_GENRE_SIMILAR:
791 if (song->genre)
792 g_checksum_update(cs, (guchar *) song->genre, -1);
793 break;
794 case META_QUERY_DATA_TYPES:
795 case META_QUERY_NO_CACHE:
796 default:
797 break;
799 retv = g_strdup(g_checksum_get_string(cs));
800 g_checksum_free(cs);
802 return retv;
806 gchar *mpd_song_checksum(const mpd_Song * song)
808 gchar *retv = NULL;
809 if (song)
811 GChecksum *cs = g_checksum_new(G_CHECKSUM_SHA256);
812 if (song->file)
813 g_checksum_update(cs, (guchar *) song->file, -1);
814 if (song->artist)
815 g_checksum_update(cs, (guchar *) song->artist, -1);
816 if (song->title)
817 g_checksum_update(cs, (guchar *) song->title, -1);
818 if (song->album)
819 g_checksum_update(cs, (guchar *) song->album, -1);
820 if (song->track)
821 g_checksum_update(cs, (guchar *) song->track, -1);
822 if (song->name)
823 g_checksum_update(cs, (guchar *) song->name, -1);
824 if (song->date)
825 g_checksum_update(cs, (guchar *) song->date, -1);
826 if (song->genre)
827 g_checksum_update(cs, (guchar *) song->genre, -1);
828 if (song->composer)
829 g_checksum_update(cs, (guchar *) song->composer, -1);
830 if (song->performer)
831 g_checksum_update(cs, (guchar *) song->performer, -1);
832 if (song->disc)
833 g_checksum_update(cs, (guchar *) song->disc, -1);
834 if (song->albumartist)
835 g_checksum_update(cs, (guchar *) song->albumartist, -1);
837 retv = g_strdup(g_checksum_get_string(cs));
838 g_checksum_free(cs);
840 return retv;
843 /* Kudos to the gnome-panel guys. */
844 void colorshift_pixbuf(GdkPixbuf * dest, GdkPixbuf * src, int shift)
846 gint i, j;
847 gint width, height, has_alpha, src_rowstride, dest_rowstride;
848 guchar *target_pixels;
849 guchar *original_pixels;
850 guchar *pix_src;
851 guchar *pix_dest;
852 int val;
853 guchar r, g, b;
855 has_alpha = gdk_pixbuf_get_has_alpha(src);
856 width = gdk_pixbuf_get_width(src);
857 height = gdk_pixbuf_get_height(src);
858 src_rowstride = gdk_pixbuf_get_rowstride(src);
859 dest_rowstride = gdk_pixbuf_get_rowstride(dest);
860 original_pixels = gdk_pixbuf_get_pixels(src);
861 target_pixels = gdk_pixbuf_get_pixels(dest);
863 for (i = 0; i < height; i++)
865 pix_dest = target_pixels + i * dest_rowstride;
866 pix_src = original_pixels + i * src_rowstride;
868 for (j = 0; j < width; j++)
870 r = *(pix_src++);
871 g = *(pix_src++);
872 b = *(pix_src++);
874 val = r + shift;
875 *(pix_dest++) = CLAMP(val, 0, 255);
877 val = g + shift;
878 *(pix_dest++) = CLAMP(val, 0, 255);
880 val = b + shift;
881 *(pix_dest++) = CLAMP(val, 0, 255);
883 if (has_alpha)
884 *(pix_dest++) = *(pix_src++);
889 /* Kudos to the gnome-panel guys. */
890 void decolor_pixbuf(GdkPixbuf * dest, GdkPixbuf * src)
892 gint i, j;
893 gint width, height, has_alpha, src_rowstride, dest_rowstride;
894 guchar *target_pixels;
895 guchar *original_pixels;
896 guchar *pix_src;
897 guchar *pix_dest;
898 gint r;
900 has_alpha = gdk_pixbuf_get_has_alpha(src);
901 width = gdk_pixbuf_get_width(src);
902 height = gdk_pixbuf_get_height(src);
903 src_rowstride = gdk_pixbuf_get_rowstride(src);
904 dest_rowstride = gdk_pixbuf_get_rowstride(dest);
905 original_pixels = gdk_pixbuf_get_pixels(src);
906 target_pixels = gdk_pixbuf_get_pixels(dest);
907 for (i = 0; i < height; i++)
909 pix_dest = target_pixels + i * dest_rowstride;
910 pix_src = original_pixels + i * src_rowstride;
912 for (j = 0; j < width; j++)
914 r = *(pix_src++);
915 r += *(pix_src++);
916 r += *(pix_src++);
918 r = CLAMP(((r)/3),0,255);
920 *(pix_dest++) = r;
921 *(pix_dest++) = r;
922 *(pix_dest++) = r;
924 if (has_alpha)
925 *(pix_dest++) = *(pix_src++);
930 void darken_pixbuf(GdkPixbuf * dest,guint factor)
932 guint i, j;
933 guint height,width;
934 gint has_alpha, dest_rowstride;
935 guchar *target_pixels;
936 guchar *pix_dest;
938 has_alpha = gdk_pixbuf_get_has_alpha(dest);
939 width = gdk_pixbuf_get_width(dest);
940 height = gdk_pixbuf_get_height(dest);
941 dest_rowstride = gdk_pixbuf_get_rowstride(dest);
942 target_pixels = gdk_pixbuf_get_pixels(dest);
943 for (i = 0; i < height; i++)
945 pix_dest = target_pixels + i * dest_rowstride;
947 for (j = 0; j < width; j++)
949 *(pix_dest++) >>= factor;
950 *(pix_dest++) >>= factor;
951 *(pix_dest++) >>= factor;
953 if (has_alpha)
954 pix_dest++;
959 static void create_directory(const gchar * url)
962 * Check if ~/.gmpc/ exists
963 * If not try to create it.
965 if (!g_file_test(url, G_FILE_TEST_EXISTS))
967 if (g_mkdir_with_parents(url, 0700) < 0)
969 g_log(LOG_DOMAIN, G_LOG_LEVEL_ERROR, "Failed to create: %s\n", url);
970 show_error_message("Failed to create config directory.");
971 abort();
975 * if it exists, check if it's a directory
977 if (!g_file_test(url, G_FILE_TEST_IS_DIR))
979 show_error_message("The config directory is not a directory.");
980 abort();
981 } else
983 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s exist and is directory", url);
988 * Create needed directories for mpd.
990 void create_gmpc_paths(void)
992 /** create path */
993 gchar *url = gmpc_get_user_path(NULL);
994 create_directory(url);
995 q_free(url);
997 url = gmpc_get_covers_path(NULL);
998 create_directory(url);
999 /* Free the path */
1000 q_free(url);
1003 mpd_Song * mpd_songDup0(const mpd_Song *song)
1005 return (song == NULL)? NULL: mpd_songDup(song);