1 /*
2 | Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net>
3 | Part of the gtkpod project.
4 |
5 | URL: http://www.gtkpod.org/
6 | URL: http://gtkpod.sourceforge.net/
7 |
8 | This program is free software; you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation; either version 2 of the License, or
11 | (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with this program; if not, write to the Free Software
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 |
22 | iTunes and iPod are trademarks of Apple
23 |
24 | This product is not supported/written/published by Apple!
25 |
26 | $Id$
27 */
28
29 /* This file provides functions for the info window as well as for the
30 * statusbar handling */
31
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <gtk/gtk.h>
37 #include "info.h"
38 #include "misc.h"
39 #include "misc_track.h"
40 #include "prefs.h"
41
42 /* pointer to info window */
43 static GtkWidget *info_window = NULL;
44
45 GladeXML *info_xml;
46
47 /* stuff for statusbar */
48 static GtkWidget *gtkpod_statusbar = NULL;
49 static GtkWidget *gtkpod_tracks_statusbar = NULL;
50 static GtkWidget *gtkpod_space_statusbar = NULL;
51 static guint statusbar_timeout_id = 0;
52 static guint statusbar_timeout = STATUSBAR_TIMEOUT;
53
54 #define SPACE_TIMEOUT 1000
55 /* lock for size related variables (used by child and parent) */
56 static GMutex *space_mutex = NULL;
57 static GThread *space_thread = NULL;
58 static gboolean space_uptodate = FALSE;
59 static gchar *space_mp = NULL; /* thread save access through mutex */
60 static iTunesDB *space_itdb = NULL; /* semi thread save access
61 * (space_itdb will not be changed
62 * while locked) */
63 static gdouble space_ipod_free = 0; /* thread save access through mutex */
64 static gdouble space_ipod_used = 0; /* thread save access through mutex */
65
66 static GList *callbacks_info_update = NULL;
67 static GList *callbacks_info_update_track_view = NULL;
68 static GList *callbacks_info_update_playlist_view = NULL;
69 static GList *callbacks_info_update_totals_view = NULL;
70
71 #if 0
72 static gdouble get_ipod_used_space(void);
73 #endif
74
75 /* callback management */
register_callback(GList ** list,info_update_callback cb)76 static void register_callback (GList **list, info_update_callback cb)
77 {
78 if(*list && g_list_index (*list, cb) != -1)
79 return;
80
81 *list = g_list_append (*list, cb);
82 }
83
unregister_callback(GList ** list,info_update_callback cb)84 static void unregister_callback (GList **list, info_update_callback cb)
85 {
86 if(*list)
87 *list = g_list_remove (*list, cb);
88 }
89
callback_call_all(GList * list)90 static void callback_call_all (GList *list)
91 {
92 for(; list; list = list->next)
93 {
94 ((info_update_callback) list->data) ();
95 }
96 }
97
register_info_update(info_update_callback cb)98 void register_info_update (info_update_callback cb)
99 {
100 register_callback (&callbacks_info_update, cb);
101 }
102
register_info_update_track_view(info_update_callback cb)103 void register_info_update_track_view (info_update_callback cb)
104 {
105 register_callback (&callbacks_info_update_track_view, cb);
106 }
107
register_info_update_playlist_view(info_update_callback cb)108 void register_info_update_playlist_view (info_update_callback cb)
109 {
110 register_callback (&callbacks_info_update_playlist_view, cb);
111 }
112
register_info_update_totals_view(info_update_callback cb)113 void register_info_update_totals_view (info_update_callback cb)
114 {
115 register_callback (&callbacks_info_update_totals_view, cb);
116 }
117
unregister_info_update(info_update_callback cb)118 void unregister_info_update (info_update_callback cb)
119 {
120 unregister_callback (&callbacks_info_update, cb);
121 }
122
unregister_info_update_track_view(info_update_callback cb)123 void unregister_info_update_track_view (info_update_callback cb)
124 {
125 unregister_callback (&callbacks_info_update_track_view, cb);
126 }
127
unregister_info_update_playlist_view(info_update_callback cb)128 void unregister_info_update_playlist_view (info_update_callback cb)
129 {
130 unregister_callback (&callbacks_info_update_playlist_view, cb);
131 }
132
unregister_info_update_totals_view(info_update_callback cb)133 void unregister_info_update_totals_view (info_update_callback cb)
134 {
135 unregister_callback (&callbacks_info_update_totals_view, cb);
136 }
137
138 /* fill in tracks, playtime and filesize from track list @tl */
fill_in_info(GList * tl,guint32 * tracks,guint32 * playtime,gdouble * filesize)139 void fill_in_info (GList *tl, guint32 *tracks,
140 guint32 *playtime, gdouble *filesize)
141 {
142 GList *gl;
143
144 g_return_if_fail (tracks);
145 g_return_if_fail (playtime);
146 g_return_if_fail (filesize);
147
148 *tracks = 0;
149 *playtime = 0;
150 *filesize = 0;
151
152 for (gl=tl; gl; gl=gl->next)
153 {
154 Track *s = gl->data;
155 *tracks += 1;
156 *playtime += s->tracklen/1000;
157 *filesize += s->size;
158 }
159 }
160
fill_label_uint(gchar * w_name,guint32 nr)161 static void fill_label_uint (gchar *w_name, guint32 nr)
162 {
163 GtkWidget *w;
164
165 g_return_if_fail (info_window);
166 g_return_if_fail (w_name);
167 w = gtkpod_xml_get_widget (info_xml, w_name);
168 if (w)
169 {
170 gchar *str = g_strdup_printf ("%u", nr);
171 gtk_label_set_text (GTK_LABEL (w), str);
172 g_free (str);
173 }
174 }
175
fill_label_time(gchar * w_name,guint32 secs)176 static void fill_label_time (gchar *w_name, guint32 secs)
177 {
178 GtkWidget *w;
179
180 g_return_if_fail (info_window);
181 g_return_if_fail (w_name);
182 w = gtkpod_xml_get_widget (info_xml, w_name);
183 if (w)
184 {
185 gchar *str = g_strdup_printf ("%u:%02u:%02u",
186 secs / 3600,
187 (secs % 3600) / 60,
188 secs % 60);
189 gtk_label_set_text (GTK_LABEL (w), str);
190 g_free (str);
191 }
192 }
193
fill_label_size(gchar * w_name,gdouble size)194 static void fill_label_size (gchar *w_name, gdouble size)
195 {
196 GtkWidget *w;
197
198 g_return_if_fail (info_window);
199 g_return_if_fail (w_name);
200 w = gtkpod_xml_get_widget (info_xml, w_name);
201 if (w)
202 {
203 gchar *str = get_filesize_as_string (size);
204 gtk_label_set_text (GTK_LABEL (w), str);
205 g_free (str);
206 }
207 }
208
fill_label_string(gchar * w_name,const char * str)209 static void fill_label_string (gchar *w_name, const char *str)
210 {
211 GtkWidget *w;
212
213 g_return_if_fail (info_window);
214 g_return_if_fail (w_name);
215 w = gtkpod_xml_get_widget (info_xml, w_name);
216 if (w)
217 {
218 gtk_label_set_text (GTK_LABEL (w), str);
219 }
220 }
221
222 /* update all sections of info window */
info_update(void)223 void info_update (void)
224 {
225 callback_call_all (callbacks_info_update);
226
227 info_update_track_view ();
228 info_update_playlist_view ();
229 info_update_totals_view ();
230 }
231
info_update_track_view_displayed(void)232 static void info_update_track_view_displayed (void)
233 {
234 guint32 tracks, playtime; /* playtime in secs */
235 gdouble filesize; /* in bytes */
236 GList *displayed;
237
238 if (!info_window) return; /* not open */
239 displayed = display_get_selected_members (prefs_get_int("sort_tab_num")-1);
240 fill_in_info (displayed, &tracks, &playtime, &filesize);
241 fill_label_uint ("tracks_displayed", tracks);
242 fill_label_time ("playtime_displayed", playtime);
243 fill_label_size ("filesize_displayed", filesize);
244 }
245
info_update_track_view_selected(void)246 static void info_update_track_view_selected (void)
247 {
248 guint32 tracks, playtime; /* playtime in secs */
249 gdouble filesize; /* in bytes */
250 GList *selected;
251
252 if (!info_window) return; /* not open */
253 selected = display_get_selection (prefs_get_int("sort_tab_num"));
254 fill_in_info (selected, &tracks, &playtime, &filesize);
255 g_list_free (selected);
256 fill_label_uint ("tracks_selected", tracks);
257 fill_label_time ("playtime_selected", playtime);
258 fill_label_size ("filesize_selected", filesize);
259 }
260
261 /* update track view section */
info_update_track_view(void)262 void info_update_track_view (void)
263 {
264 callback_call_all (callbacks_info_update_track_view);
265
266 if (!info_window) return; /* not open */
267 info_update_track_view_displayed ();
268 info_update_track_view_selected ();
269 }
270
271 /* update playlist view section */
info_update_playlist_view(void)272 void info_update_playlist_view (void)
273 {
274 callback_call_all (callbacks_info_update_playlist_view);
275
276 guint32 tracks, playtime; /* playtime in secs */
277 gdouble filesize; /* in bytes */
278 GList *tl;
279
280 if (!info_window) return; /* not open */
281 tl = display_get_selected_members (-1);
282 fill_in_info (tl, &tracks, &playtime, &filesize);
283 fill_label_uint ("playlist_tracks", tracks);
284 fill_label_time ("playlist_playtime", playtime);
285 fill_label_size ("playlist_filesize", filesize);
286 }
287
288
289 /* Get the local itdb */
get_itdb_local(void)290 iTunesDB *get_itdb_local (void)
291 {
292 struct itdbs_head *itdbs_head;
293 GList *gl;
294
295 g_return_val_if_fail (gtkpod_window, NULL);
296 itdbs_head = g_object_get_data (G_OBJECT (gtkpod_window),
297 "itdbs_head");
298 if (!itdbs_head) return NULL;
299 for (gl=itdbs_head->itdbs; gl; gl=gl->next)
300 {
301 iTunesDB *itdb = gl->data;
302 g_return_val_if_fail (itdb, NULL);
303 if (itdb->usertype & GP_ITDB_TYPE_LOCAL)
304 return itdb;
305 }
306 return NULL;
307 }
308
309
310 /* Get the iPod itdb */
311 /* FIXME: This function must be expanded if support for several iPods
312 is implemented */
get_itdb_ipod(void)313 iTunesDB *get_itdb_ipod (void)
314 {
315 struct itdbs_head *itdbs_head;
316 GList *gl;
317
318 g_return_val_if_fail (gtkpod_window, NULL);
319 itdbs_head = g_object_get_data (G_OBJECT (gtkpod_window),
320 "itdbs_head");
321 if (!itdbs_head) return NULL;
322 for (gl=itdbs_head->itdbs; gl; gl=gl->next)
323 {
324 iTunesDB *itdb = gl->data;
325 g_return_val_if_fail (itdb, NULL);
326 if (itdb->usertype & GP_ITDB_TYPE_IPOD)
327 return itdb;
328 }
329 return NULL;
330 }
331
332 /* update "free space" section of totals view */
info_update_totals_view_space(void)333 static void info_update_totals_view_space (void)
334 {
335 gdouble nt_filesize, del_filesize;
336 guint32 nt_tracks, del_tracks;
337 iTunesDB *itdb;
338
339 if (!info_window) return;
340 itdb = get_itdb_ipod ();
341 if (itdb)
342 {
343 gp_info_nontransferred_tracks (itdb, &nt_filesize, &nt_tracks);
344 fill_label_uint ("non_transferred_tracks", nt_tracks);
345 fill_label_size ("non_transferred_filesize", nt_filesize);
346 gp_info_deleted_tracks (itdb, &del_filesize, &del_tracks);
347 fill_label_uint ("deleted_tracks", del_tracks);
348 fill_label_size ("deleted_filesize", del_filesize);
349 if (!get_offline (itdb))
350 {
351 if (ipod_connected ())
352 {
353 gdouble free_space = get_ipod_free_space()
354 + del_filesize - nt_filesize;
355 fill_label_size ("free_space", free_space);
356 }
357 else
358 {
359 fill_label_string ("free_space", _("n/c"));
360 }
361 }
362 else
363 {
364 fill_label_string ("free_space", _("offline"));
365 }
366 }
367 }
368
369 /* update "totals" view section */
info_update_totals_view(void)370 void info_update_totals_view (void)
371 {
372 guint32 tracks=0, playtime=0; /* playtime in secs */
373 gdouble filesize=0; /* in bytes */
374 Playlist *pl;
375 iTunesDB *itdb;
376
377 callback_call_all (callbacks_info_update_totals_view);
378
379 if (!info_window) return; /* not open */
380
381 itdb = get_itdb_ipod ();
382 if (itdb)
383 {
384 pl = itdb_playlist_mpl (itdb);
385 g_return_if_fail (pl);
386 fill_in_info (pl->members, &tracks, &playtime, &filesize);
387 fill_label_uint ("total_playlists_ipod",
388 itdb_playlists_number (itdb)-1);
389 fill_label_uint ("total_tracks_ipod", tracks);
390 fill_label_time ("total_playtime_ipod", playtime);
391 fill_label_size ("total_filesize_ipod", filesize);
392 }
393 itdb = get_itdb_local ();
394 if (itdb)
395 {
396 pl = itdb_playlist_mpl (itdb);
397 g_return_if_fail (pl);
398 fill_in_info (pl->members, &tracks, &playtime, &filesize);
399 fill_label_uint ("total_playlists_local",
400 itdb_playlists_number (itdb)-1);
401 fill_label_uint ("total_tracks_local", tracks);
402 fill_label_time ("total_playtime_local", playtime);
403 fill_label_size ("total_filesize_local", filesize);
404 }
405 info_update_totals_view_space ();
406 }
407
408 /*------------------------------------------------------------------*\
409 * *
410 * Functions for Statusbar *
411 * *
412 \*------------------------------------------------------------------*/
413
414 void
gtkpod_statusbar_init(void)415 gtkpod_statusbar_init(void)
416 {
417 gtkpod_statusbar = gtkpod_xml_get_widget (main_window_xml, "gtkpod_status");
418 statusbar_timeout = STATUSBAR_TIMEOUT;
419 }
420
421 static gint
gtkpod_statusbar_clear(gpointer data)422 gtkpod_statusbar_clear(gpointer data)
423 {
424 if(gtkpod_statusbar)
425 {
426 gtk_statusbar_pop(GTK_STATUSBAR(gtkpod_statusbar), 1);
427 }
428 statusbar_timeout_id = 0; /* indicate that timeout handler is
429 clear (0 cannot be a handler id) */
430 return FALSE;
431 }
432
433
434 static void
gtkpod_statusbar_reset_timeout(void)435 gtkpod_statusbar_reset_timeout (void)
436 {
437 if (statusbar_timeout_id != 0) /* remove last timeout, if still present */
438 gtk_timeout_remove (statusbar_timeout_id);
439 statusbar_timeout_id = gtk_timeout_add (statusbar_timeout,
440 (GtkFunction) gtkpod_statusbar_clear,
441 NULL);
442 }
443
444 void
gtkpod_statusbar_timeout(guint timeout)445 gtkpod_statusbar_timeout (guint timeout)
446 {
447 if (timeout == 0)
448 statusbar_timeout = STATUSBAR_TIMEOUT;
449 else
450 statusbar_timeout = timeout;
451
452 gtkpod_statusbar_reset_timeout ();
453 }
454
455
456 void
gtkpod_statusbar_message(const gchar * message,...)457 gtkpod_statusbar_message(const gchar *message, ...)
458 {
459 if(gtkpod_statusbar)
460 {
461 va_list arg;
462 gchar *text;
463 guint context = 1;
464
465 va_start (arg, message);
466 text = g_strdup_vprintf (message, arg);
467 va_end (arg);
468
469 gtk_statusbar_pop(GTK_STATUSBAR(gtkpod_statusbar), context);
470 gtk_statusbar_push(GTK_STATUSBAR(gtkpod_statusbar), context, text);
471
472 g_free (text);
473
474 gtkpod_statusbar_reset_timeout ();
475 }
476 }
477
478 void
gtkpod_tracks_statusbar_init()479 gtkpod_tracks_statusbar_init()
480 {
481 gtkpod_tracks_statusbar =
482 gtkpod_xml_get_widget (main_window_xml, "tracks_statusbar");
483 gtkpod_tracks_statusbar_update();
484 }
485
486 void
gtkpod_tracks_statusbar_update(void)487 gtkpod_tracks_statusbar_update(void)
488 {
489 if(gtkpod_tracks_statusbar)
490 {
491 gchar *buf;
492 Playlist *pl;
493 pl = pm_get_selected_playlist ();
494 /* select of which iTunesDB data should be displayed */
495 if (pl)
496 {
497 iTunesDB *itdb = pl->itdb;
498 g_return_if_fail (itdb);
499
500 buf = g_strdup_printf (_(" P:%d T:%d/%d"),
501 itdb_playlists_number (itdb) - 1,
502 tm_get_nr_of_tracks (),
503 itdb_tracks_number (itdb));
504 }
505 else
506 {
507 buf = g_strdup ("");
508 }
509 /* gets called before itdbs are setup up -> fail silently */
510 /* g_return_if_fail (itdb);*/
511
512 gtk_statusbar_pop(GTK_STATUSBAR(gtkpod_tracks_statusbar), 1);
513 gtk_statusbar_push(GTK_STATUSBAR(gtkpod_tracks_statusbar), 1, buf);
514 g_free (buf);
515 }
516 /* Update info window */
517 info_update ();
518 }
519
520 /*------------------------------------------------------------------*\
521 * *
522 * free space stuff *
523 * *
524 \*------------------------------------------------------------------*/
525
526
527 /* Since the mount point is used by two separate threads, it can only
528 be accessed securely by using a locking mechanism. Therefore we
529 keep a copy of the mount point here. Access must only be done
530 after locking. */
space_set_ipod_itdb(iTunesDB * itdb)531 void space_set_ipod_itdb (iTunesDB *itdb)
532 {
533 const gchar *mp = NULL;
534
535 if (itdb)
536 {
537 ExtraiTunesDBData *eitdb = itdb->userdata;
538 g_return_if_fail (eitdb);
539
540 if (!eitdb->ipod_ejected)
541 {
542 mp = itdb_get_mountpoint (itdb);
543 }
544 }
545
546 if (space_mutex) g_mutex_lock (space_mutex);
547
548 space_itdb = itdb;
549
550 /* update the free space data if mount point changed */
551 if (!space_mp || !mp || (strcmp (space_mp, mp) != 0))
552 {
553 g_free (space_mp);
554 space_mp = g_strdup (mp);
555
556 space_data_update ();
557 }
558
559 if (space_mutex) g_mutex_unlock (space_mutex);
560
561 }
562
563 /* retrieve the currently set ipod itdb -- needed in case the itdb is
564 deleted */
space_get_ipod_itdb(void)565 iTunesDB *space_get_ipod_itdb (void)
566 {
567 return space_itdb;
568 }
569
570
571
572 /* iPod space has to be reread */
space_data_update(void)573 void space_data_update (void)
574 {
575 space_uptodate = FALSE;
576 }
577
578
579 /* Is the iPod connected? If space_ipod_used and space_ipod_free are
580 both zero, we assume the iPod is not connected */
ipod_connected(void)581 gboolean ipod_connected (void)
582 {
583 gboolean result;
584 g_return_val_if_fail (space_mutex!=NULL, FALSE);
585 g_mutex_lock (space_mutex);
586 if ((space_ipod_used == 0) && (space_ipod_free == 0)) result = FALSE;
587 else result = TRUE;
588 g_mutex_unlock (space_mutex);
589 return result;
590 }
591
592
593
594 /* we'll use statvfs to determine free space on the iPod where
595 available, df otherwise */
596 #ifdef HAVE_STATVFS
597 #include <sys/types.h>
598 #include <sys/statvfs.h>
599 /* update space_ipod_free and space_ipod_used */
th_space_update(void)600 static void th_space_update (void)
601 {
602 gchar *mp=NULL;
603 struct statvfs stat;
604 int status;
605
606 g_mutex_lock (space_mutex);
607
608 /* don't read info when in offline mode */
609 if (space_itdb && !get_offline (space_itdb))
610 {
611 mp = g_strdup (space_mp);
612 }
613 if (mp)
614 {
615 status = statvfs (mp, &stat);
616 if (status != 0) {
617 /* XXX: why would this fail - what to do here??? */
618 goto done;
619 }
620 space_ipod_free = (gdouble)stat.f_bavail * stat.f_frsize;
621 space_ipod_used = ((gdouble)stat.f_blocks * stat.f_frsize) -
622 space_ipod_free;
623 space_uptodate = TRUE;
624
625 } else { /* mp == NULL */
626
627 /* this is set even if offline mode */
628 space_ipod_free = 0;
629 space_ipod_used = 0;
630 space_uptodate = FALSE; /* this way we will detect when the
631 iPod is connected */
632 }
633
634 done:
635 g_mutex_unlock (space_mutex);
636 g_free (mp);
637 }
638
639 #else
640 static gchar*
get_drive_stats_from_df(const gchar * mp)641 get_drive_stats_from_df(const gchar *mp)
642 {
643 FILE *fp;
644 gchar buf[PATH_MAX+1];
645 gchar bufc[PATH_MAX+1];
646 gchar *bufp;
647 gchar *result = NULL;
648 guint bytes_read = 0;
649
650 #if 0
651 GTimeVal gtv1, gtv2;
652 long micros;
653 g_get_current_time (>v1);
654 #endif
655
656 if (g_file_test (mp, G_FILE_TEST_EXISTS))
657 {
658 gchar *df_str = getenv ("GTKPOD_DF_COMMAND");
659 if (df_str == NULL) df_str = "df -k -P";
660 if (strlen (df_str))
661 {
662 snprintf(bufc, PATH_MAX, "%s \"%s\"", df_str, mp);
663 fp = popen(bufc, "r");
664 if(fp)
665 {
666 if((bytes_read = fread(buf, 1, PATH_MAX, fp)) > 0)
667 {
668 if((bufp = strchr (buf, '\n')))
669 {
670 int i = 0;
671 int j = 0;
672 gchar buf2[PATH_MAX+3];
673
674 ++bufp; /* skip '\n' */
675 while((bufp - buf + i < bytes_read) &&
676 (j < PATH_MAX))
677 {
678 while(!g_ascii_isspace(bufp[i]) &&
679 (j<PATH_MAX))
680 {
681 buf2[j++] = bufp[i++];
682 }
683 buf2[j++] = ' ';
684 while((bufp - buf + i < bytes_read) &&
685 g_ascii_isspace(bufp[i]))
686 {
687 i++;
688 }
689 }
690 buf2[j] = '\0';
691 result = g_strdup_printf("%s", buf2);
692 }
693 }
694 pclose(fp);
695 }
696 }
697 }
698 #if 0
699 g_get_current_time (>v2);
700 micros = (gtv2.tv_sec-gtv1.tv_sec)*10000000 + (gtv2.tv_usec-gtv1.tv_usec);
701 printf ("df: %ld usec\n", micros);
702 #endif
703 return(result);
704 }
705
706
707 /* update space_ipod_free and space_ipod_used */
th_space_update(void)708 static void th_space_update (void)
709 {
710 gchar *mp=NULL, *line=NULL;
711 gchar **tokens = NULL;
712
713 g_mutex_lock (space_mutex);
714 mp = g_strdup (space_mp);
715 g_mutex_unlock (space_mutex);
716
717 g_mutex_lock (space_mutex);
718
719 if (line) tokens = g_strsplit(line, " ", 5);
720 if (tokens && tokens[0] && tokens[1] && tokens[2] && tokens[3])
721 {
722 space_ipod_free = g_strtod (tokens[3], NULL) * 1024;
723 space_ipod_used = g_strtod (tokens[2], NULL) * 1024;
724 space_uptodate = TRUE;
725 }
726 else
727 {
728 /* this is set even if offline mode */
729 space_ipod_free = 0;
730 space_ipod_used = 0;
731 space_uptodate = FALSE; /* this way we will detect when the
732 iPod is connected */
733 }
734 g_mutex_unlock (space_mutex);
735 g_free (mp);
736 g_strfreev(tokens);
737 }
738 #endif
739
740
741 /* keep space_ipod_free/used updated in regular intervals */
th_space_thread(gpointer gp)742 static gpointer th_space_thread (gpointer gp)
743 {
744 struct timespec req;
745
746 req.tv_sec = SPACE_TIMEOUT / 1000;
747 req.tv_nsec = (SPACE_TIMEOUT % 1000) * 1000000;
748
749 for (;;)
750 {
751 nanosleep (&req, NULL);
752 if (!space_uptodate) th_space_update ();
753 }
754 /* To make gcc happy (never reached) */
755 return (gpointer)NULL;
756 }
757
758
759 /* in Bytes */
get_ipod_free_space(void)760 gdouble get_ipod_free_space(void)
761 {
762 gdouble result;
763 g_mutex_lock (space_mutex);
764 result = space_ipod_free;
765 g_mutex_unlock (space_mutex);
766 return result;
767 }
768
769 #if 0
770 /* in Bytes */
771 static gdouble get_ipod_used_space(void)
772 {
773 gdouble result;
774 g_mutex_lock (space_mutex);
775 result = space_ipod_used;
776 g_mutex_unlock (space_mutex);
777 return result;
778 }
779 #endif
780
781
782 /* @size: size in B */
783 gchar*
get_filesize_as_string(gdouble size)784 get_filesize_as_string(gdouble size)
785 {
786 guint i = 0;
787 gchar *result = NULL;
788 gchar *sizes[] = { _("B"), _("kB"), _("MB"), _("GB"), _("TB"), NULL };
789
790 while((fabs(size) > 1024) && (i<4))
791 {
792 size /= 1024;
793 ++i;
794 }
795 if (i>0)
796 {
797 if (fabs(size) < 10)
798 result = g_strdup_printf("%0.2f %s", size, sizes[i]);
799 else if (fabs(size) < 100)
800 result = g_strdup_printf("%0.1f %s", size, sizes[i]);
801 else
802 result = g_strdup_printf("%0.0f %s", size, sizes[i]);
803 }
804 else
805 { /* Bytes do not have decimal places */
806 result = g_strdup_printf ("%0.0f %s", size, sizes[i]);
807 }
808 return result;
809 }
810
811 static guint
gtkpod_space_statusbar_update(void)812 gtkpod_space_statusbar_update(void)
813 {
814 if(space_itdb && gtkpod_space_statusbar)
815 {
816 gchar *buf = NULL;
817 gchar *str = NULL;
818
819 if (!get_offline (space_itdb))
820 {
821 if (ipod_connected ())
822 {
823 gdouble left, pending, deleted;
824
825 gp_info_deleted_tracks (space_itdb, &deleted, NULL);
826 gp_info_nontransferred_tracks (space_itdb, &pending, NULL);
827 left = get_ipod_free_space() + deleted;
828 if((left-pending) > 0)
829 {
830 str = get_filesize_as_string(left - pending);
831 buf = g_strdup_printf (_(" %s Free"), str);
832 }
833 else
834 {
835 str = get_filesize_as_string(pending - left);
836 buf = g_strdup_printf (_(" %s Pending"), str);
837 }
838 }
839 else
840 {
841 buf = g_strdup (_(" disconnected"));
842 }
843 }
844 else
845 {
846 buf = g_strdup (_("offline"));
847 }
848 gtk_statusbar_pop(GTK_STATUSBAR(gtkpod_space_statusbar), 1);
849 gtk_statusbar_push(GTK_STATUSBAR(gtkpod_space_statusbar), 1, buf);
850 g_free (buf);
851 g_free (str);
852 }
853 info_update_totals_view_space ();
854 return TRUE;
855 }
856
857 void
gtkpod_space_statusbar_init(void)858 gtkpod_space_statusbar_init(void)
859 {
860 gtkpod_space_statusbar = gtkpod_xml_get_widget (main_window_xml, "space_statusbar");
861
862 if (!space_mutex)
863 {
864 space_mutex = g_mutex_new ();
865 if (!space_mp)
866 {
867 iTunesDB *itdb = gp_get_ipod_itdb ();
868
869 if (itdb)
870 {
871 space_mp = get_itdb_prefs_string (itdb, KEY_MOUNTPOINT);
872 th_space_update (); /* make sure we have current data */
873 }
874 }
875 space_thread = g_thread_create (th_space_thread,
876 NULL, FALSE, NULL);
877 }
878 gtkpod_space_statusbar_update();
879 gtk_timeout_add(1000, (GtkFunction) gtkpod_space_statusbar_update, NULL);
880 }
881
882
883
884 /*------------------------------------------------------------------*\
885 * *
886 * Frequently used error messages *
887 * *
888 \*------------------------------------------------------------------*/
889
message_sb_no_itdb_selected()890 void message_sb_no_itdb_selected ()
891 {
892 gtkpod_statusbar_message (_("No database or playlist selected"));
893 }
894
message_sb_no_tracks_selected()895 void message_sb_no_tracks_selected ()
896 {
897 gtkpod_statusbar_message (_("No tracks selected"));
898 }
899
message_sb_no_playlist_selected()900 void message_sb_no_playlist_selected ()
901 {
902 gtkpod_statusbar_message (_("No playlist selected"));
903 }
904
message_sb_no_ipod_itdb_selected()905 void message_sb_no_ipod_itdb_selected ()
906 {
907 gtkpod_statusbar_message (_("No iPod or iPod playlist selected"));
908 }
909
910