31
32
#include <glib/gi18n.h>
32
33
#include <glib/gstdio.h> /* g_unlink() */
34
#include <gio/gio.h> /* g_file_trash() */
35
#include <gio/gio.h> /* g_file_trash() */
36
37
#ifdef HAVE_DBUS_GLIB
37
#include <dbus/dbus-glib.h>
38
#include <dbus/dbus-glib.h>
40
41
#include <libevent/evhttp.h>
42
43
#include <libtransmission/transmission.h> /* TR_RATIO_NA, TR_RATIO_INF */
43
44
#include <libtransmission/utils.h> /* tr_inf */
45
#include <libtransmission/version.h> /* tr_inf */
46
49
#include "tr-prefs.h"
50
tr_strcmp( const char * a, const char * b )
52
if( a && b ) return strcmp( a, b );
59
53
tr_strlratio( char * buf, double ratio, size_t buflen )
61
if( (int)ratio == TR_RATIO_NA )
62
g_strlcpy( buf, _( "None" ), buflen );
63
else if( (int)ratio == TR_RATIO_INF )
64
g_strlcpy( buf, "\xE2\x88\x9E", buflen );
65
else if( ratio < 10.0 )
66
g_snprintf( buf, buflen, "%'.2f", ratio );
67
else if( ratio < 100.0 )
68
g_snprintf( buf, buflen, "%'.1f", ratio );
70
g_snprintf( buf, buflen, "%'.0f", ratio );
55
return tr_strratio( buf, buflen, ratio, "\xE2\x88\x9E" );
74
58
#define KILOBYTE_FACTOR 1024.0
75
#define MEGABYTE_FACTOR (1024.0 * 1024.0)
76
#define GIGABYTE_FACTOR (1024.0 * 1024.0 * 1024.0)
59
#define MEGABYTE_FACTOR ( 1024.0 * 1024.0 )
60
#define GIGABYTE_FACTOR ( 1024.0 * 1024.0 * 1024.0 )
79
tr_strlsize( char * buf, guint64 size, size_t buflen )
63
tr_strlsize( char * buf,
82
68
g_strlcpy( buf, _( "None" ), buflen );
83
#if GLIB_CHECK_VERSION(2,16,0)
69
#if GLIB_CHECK_VERSION( 2, 16, 0 )
85
72
char * tmp = g_format_size_for_display( size );
86
73
g_strlcpy( buf, tmp, buflen );
90
77
else if( size < (guint64)KILOBYTE_FACTOR )
91
g_snprintf( buf, buflen, ngettext("%'u byte", "%'u bytes", (guint)size), (guint)size );
78
g_snprintf( buf, buflen,
79
ngettext( "%'u byte", "%'u bytes",
80
(guint)size ), (guint)size );
93
83
gdouble displayed_size;
94
if (size < (guint64)MEGABYTE_FACTOR) {
84
if( size < (guint64)MEGABYTE_FACTOR )
95
86
displayed_size = (gdouble) size / KILOBYTE_FACTOR;
96
g_snprintf( buf, buflen, _("%'.1f KB"), displayed_size );
97
} else if (size < (guint64)GIGABYTE_FACTOR) {
87
g_snprintf( buf, buflen, _( "%'.1f KB" ), displayed_size );
89
else if( size < (guint64)GIGABYTE_FACTOR )
98
91
displayed_size = (gdouble) size / MEGABYTE_FACTOR;
99
g_snprintf( buf, buflen, _("%'.1f MB"), displayed_size );
92
g_snprintf( buf, buflen, _( "%'.1f MB" ), displayed_size );
101
96
displayed_size = (gdouble) size / GIGABYTE_FACTOR;
102
g_snprintf( buf, buflen, _("%'.1f GB"), displayed_size );
97
g_snprintf( buf, buflen, _( "%'.1f GB" ), displayed_size );
110
tr_strlspeed( char * buf, double kb_sec, size_t buflen )
105
tr_strlspeed( char * buf,
112
109
const double speed = kb_sec;
114
if ( speed < 1000.0 ) /* 0.0 KB to 999.9 KB */
111
if( speed < 1000.0 ) /* 0.0 KB to 999.9 KB */
115
112
g_snprintf( buf, buflen, _( "%'.1f KB/s" ), speed );
116
113
else if( speed < 102400.0 ) /* 0.98 MB to 99.99 MB */
117
g_snprintf( buf, buflen, _( "%'.2f MB/s" ), (speed/1024) );
114
g_snprintf( buf, buflen, _( "%'.2f MB/s" ), ( speed / KILOBYTE_FACTOR ) );
118
115
else if( speed < 1024000.0 ) /* 100.0 MB to 999.9 MB */
119
g_snprintf( buf, buflen, _( "%'.1f MB/s" ), (speed/1024) );
116
g_snprintf( buf, buflen, _( "%'.1f MB/s" ), ( speed / MEGABYTE_FACTOR ) );
120
117
else /* insane speeds */
121
g_snprintf( buf, buflen, _( "%'.2f GB/s" ), (speed/1048576) );
118
g_snprintf( buf, buflen, _( "%'.2f GB/s" ), ( speed / GIGABYTE_FACTOR ) );
127
tr_strltime( char * buf, int seconds, size_t buflen )
124
tr_strltime( char * buf,
128
int days, hours, minutes;
129
char d[128], h[128], m[128], s[128];
132
131
if( seconds < 0 )
137
g_snprintf( buf, buflen, ngettext( "%'d second", "%'d seconds", (int)seconds ), (int) seconds );
141
if( seconds < ( 60 * 60 ) )
143
const int minutes = ( seconds + 30 ) / 60;
144
g_snprintf( buf, buflen, ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
148
hours = seconds / ( 60 * 60 );
150
if( seconds < ( 60 * 60 * 4 ) )
155
const int minutes = ( seconds - hours * 60 * 60 + 30 ) / 60;
157
g_snprintf( h, sizeof(h), ngettext( "%'d hour", "%'d hours", hours ), hours );
158
g_snprintf( m, sizeof(m), ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
159
g_snprintf( buf, buflen, "%s, %s", h, m );
165
g_snprintf( buf, buflen, ngettext( "%'d hour", "%'d hours", hours ), hours );
169
days = seconds / ( 60 * 60 * 24 );
170
g_snprintf( buf, buflen, ngettext( "%'d day", "%'d days", days ), days );
134
days = seconds / 86400;
135
hours = ( seconds % 86400 ) / 3600;
136
minutes = ( seconds % 3600 ) / 60;
137
seconds = ( seconds % 3600 ) % 60;
139
g_snprintf( d, sizeof( d ), ngettext( "%'d day", "%'d days",
141
g_snprintf( h, sizeof( h ), ngettext( "%'d hour", "%'d hours",
143
g_snprintf( m, sizeof( m ),
144
ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
145
g_snprintf( s, sizeof( s ),
146
ngettext( "%'d second", "%'d seconds", seconds ), seconds );
150
if( days >= 4 || !hours )
152
g_strlcpy( buf, d, buflen );
156
g_snprintf( buf, buflen, "%s, %s", d, h );
161
if( hours >= 4 || !minutes )
163
g_strlcpy( buf, h, buflen );
167
g_snprintf( buf, buflen, "%s, %s", h, m );
172
if( minutes >= 4 || !seconds )
174
g_strlcpy( buf, m, buflen );
178
g_snprintf( buf, buflen, "%s, %s", m, s );
183
g_strlcpy( buf, s, buflen );
176
rfc822date (guint64 epoch_msec)
190
gtr_localtime( time_t time )
178
const time_t secs = epoch_msec / 1000;
179
const struct tm tm = *localtime (&secs);
181
strftime( buf, sizeof(buf), "%a, %d %b %Y %T %Z", &tm );
192
const struct tm tm = *localtime( &time );
193
char buf[256], *eoln;
195
g_strlcpy( buf, asctime( &tm ), sizeof( buf ) );
196
if( ( eoln = strchr( buf, '\n' ) ) )
182
199
return g_locale_to_utf8( buf, -1, NULL, NULL, NULL );
186
mkdir_p( const char * path, mode_t mode )
188
#if GLIB_CHECK_VERSION( 2, 8, 0)
203
gtr_localtime2( char * buf, time_t time, size_t buflen )
205
char * tmp = gtr_localtime( time );
206
g_strlcpy( buf, tmp, buflen );
212
mkdir_p( const char * path,
215
#if GLIB_CHECK_VERSION( 2, 8, 0 )
189
216
return !g_mkdir_with_parents( path, mode );
191
218
return !tr_mkdirp( path, mode );
196
223
dupstrlist( GSList * l )
198
225
GSList * ret = NULL;
199
for( ; l!=NULL; l=l->next )
227
for( ; l != NULL; l = l->next )
200
228
ret = g_slist_prepend( ret, g_strdup( l->data ) );
201
229
return g_slist_reverse( ret );
205
joinstrlist(GSList *list, char *sep)
233
joinstrlist( GSList *list,
208
GString *gstr = g_string_new (NULL);
209
for (l=list; l!=NULL; l=l->next) {
210
g_string_append (gstr, (char*)l->data);
212
g_string_append (gstr, (sep));
214
return g_string_free (gstr, FALSE);
237
GString *gstr = g_string_new ( NULL );
239
for( l = list; l != NULL; l = l->next )
241
g_string_append ( gstr, (char*)l->data );
242
if( l->next != NULL )
243
g_string_append ( gstr, ( sep ) );
245
return g_string_free ( gstr, FALSE );
218
freestrlist(GSList *list)
249
freestrlist( GSList *list )
220
g_slist_foreach (list, (GFunc)g_free, NULL);
251
g_slist_foreach ( list, (GFunc)g_free, NULL );
252
g_slist_free ( list );
225
256
decode_uri( const char * uri )
227
258
gboolean in_query = FALSE;
228
char * ret = g_new( char, strlen( uri ) + 1 );
230
for( ; uri && *uri; ) {
259
char * ret = g_new( char, strlen( uri ) + 1 );
262
for( ; uri && *uri; )
234
else if( ch=='+' && in_query )
267
else if( ch == '+' && in_query )
236
else if( ch=='%' && isxdigit((unsigned char)uri[1])
237
&& isxdigit((unsigned char)uri[2])) {
269
else if( ch == '%' && isxdigit( (unsigned char)uri[1] )
270
&& isxdigit( (unsigned char)uri[2] ) )
238
272
char buf[3] = { uri[1], uri[2], '\0' };
239
273
ch = (char) g_ascii_strtoull( buf, NULL, 16 );
302
327
static GtkWidget *
303
verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
304
const char * format, va_list ap )
308
GSList *funcdata = NULL;
310
msg = g_strdup_vprintf(format, ap);
313
dialog = gtk_message_dialog_new(
314
NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
316
dialog = gtk_message_dialog_new(wind,
317
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
318
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
321
funcdata = g_slist_append( funcdata, (gpointer)func );
322
funcdata = g_slist_append( funcdata, data );
324
g_signal_connect(dialog, "response", G_CALLBACK(onErrorResponse), funcdata);
331
errmsg( GtkWindow * wind, const char * format, ... )
328
verrmsg_full( GtkWindow * wind,
336
GSList * funcdata = NULL;
338
msg = g_strdup_vprintf( format, ap );
341
dialog = gtk_message_dialog_new(
342
NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg );
344
dialog = gtk_message_dialog_new(
347
GTK_DIALOG_DESTROY_WITH_PARENT,
348
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
353
funcdata = g_slist_append( funcdata, (gpointer)func );
354
funcdata = g_slist_append( funcdata, data );
356
g_signal_connect( dialog, "response", G_CALLBACK(
357
onErrorResponse ), funcdata );
364
addTorrentErrorDialog( GtkWidget * child,
366
const char * filename )
376
fmt = _( "The torrent file \"%s\" contains invalid data." );
380
fmt = _( "The torrent file \"%s\" is already in use." ); break;
384
"The torrent file \"%s\" encountered an unknown error." );
387
secondary = g_strdup_printf( fmt, filename );
388
win = ( !child || GTK_IS_WINDOW( child ) )
390
: gtk_widget_get_ancestor( child ? GTK_WIDGET(
391
child ) : NULL, GTK_TYPE_WINDOW );
392
w = gtk_message_dialog_new( GTK_WINDOW( win ),
393
GTK_DIALOG_DESTROY_WITH_PARENT,
396
_( "Error opening torrent" ) );
397
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ),
399
g_signal_connect_swapped( w, "response",
400
G_CALLBACK( gtk_widget_destroy ), w );
401
gtk_widget_show_all( w );
406
errmsg( GtkWindow * wind,
333
410
GtkWidget * dialog;
365
typedef void (PopupFunc)(GtkWidget*, GdkEventButton*);
445
typedef void ( PopupFunc )( GtkWidget*, GdkEventButton* );
367
447
/* pop up the context menu if a user right-clicks.
368
448
if the row they right-click on isn't selected, select it. */
371
on_tree_view_button_pressed (GtkWidget * view,
372
GdkEventButton * event,
375
GtkTreeView * tv = GTK_TREE_VIEW( view );
377
if (event->type == GDK_BUTTON_PRESS && event->button == 3)
379
GtkTreeSelection * selection = gtk_tree_view_get_selection(tv);
381
if (gtk_tree_view_get_path_at_pos (tv,
384
&path, NULL, NULL, NULL))
386
if (!gtk_tree_selection_path_is_selected (selection, path))
388
gtk_tree_selection_unselect_all (selection);
389
gtk_tree_selection_select_path (selection, path);
391
gtk_tree_path_free(path);
394
((PopupFunc*)func)(view, event);
451
on_tree_view_button_pressed( GtkWidget * view,
452
GdkEventButton * event,
455
GtkTreeView * tv = GTK_TREE_VIEW( view );
457
if( event->type == GDK_BUTTON_PRESS && event->button == 3 )
459
GtkTreeSelection * selection = gtk_tree_view_get_selection( tv );
461
if( gtk_tree_view_get_path_at_pos ( tv,
464
&path, NULL, NULL, NULL ) )
466
if( !gtk_tree_selection_path_is_selected ( selection, path ) )
468
gtk_tree_selection_unselect_all ( selection );
469
gtk_tree_selection_select_path ( selection, path );
471
gtk_tree_path_free( path );
474
( (PopupFunc*)func )( view, event );
482
/* if the user clicked in an empty area of the list,
483
* clear all the selections. */
485
on_tree_view_button_released( GtkWidget * view,
486
GdkEventButton * event,
487
gpointer unused UNUSED )
489
GtkTreeView * tv = GTK_TREE_VIEW( view );
491
if( !gtk_tree_view_get_path_at_pos ( tv,
494
NULL, NULL, NULL, NULL ) )
496
GtkTreeSelection * selection = gtk_tree_view_get_selection( tv );
497
gtk_tree_selection_unselect_all ( selection );
403
505
tr_object_ref_sink( gpointer object )
405
#if GLIB_CHECK_VERSION(2,10,0)
507
#if GLIB_CHECK_VERSION( 2, 10, 0 )
406
508
g_object_ref_sink( object );
408
510
g_object_ref( object );
458
char * argv[] = { "xdg-open", (char*)path, NULL };
570
char * argv[] = { (char*)"xdg-open", (char*)path, NULL };
459
571
g_spawn_async( NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
460
572
NULL, NULL, NULL, NULL );
465
#ifdef HAVE_DBUS_GLIB
467
get_hibernation_inhibit_proxy( void )
469
GError * error = NULL;
470
DBusGConnection * conn;
472
conn = dbus_g_bus_get( DBUS_BUS_SESSION, &error );
475
g_warning ("DBUS cannot connect : %s", error->message);
476
g_error_free (error);
480
return dbus_g_proxy_new_for_name (conn,
481
"org.freedesktop.PowerManagement",
482
"/org/freedesktop/PowerManagement/Inhibit",
483
"org.freedesktop.PowerManagement.Inhibit" );
577
#define VALUE_SERVICE_NAME "com.transmissionbt.Transmission"
578
#define VALUE_SERVICE_OBJECT_PATH "/com/transmissionbt/Transmission"
579
#define VALUE_SERVICE_INTERFACE "com.transmissionbt.Transmission"
582
gtr_dbus_add_torrent( const char * filename )
584
static gboolean success = FALSE;
586
#ifdef HAVE_DBUS_GLIB
587
DBusGProxy * proxy = NULL;
589
DBusGConnection * conn;
590
if( ( conn = dbus_g_bus_get( DBUS_BUS_SESSION, &err ) ) )
591
proxy = dbus_g_proxy_new_for_name ( conn, VALUE_SERVICE_NAME,
592
VALUE_SERVICE_OBJECT_PATH,
593
VALUE_SERVICE_INTERFACE );
595
g_message( "err: %s", err->message );
597
dbus_g_proxy_call( proxy, "AddFile", &err,
598
G_TYPE_STRING, filename,
600
G_TYPE_BOOLEAN, &success,
603
g_message( "err: %s", err->message );
605
g_object_unref( proxy );
606
dbus_g_connection_unref( conn );
612
gtr_dbus_present_window( void )
614
static gboolean success = FALSE;
616
#ifdef HAVE_DBUS_GLIB
617
DBusGProxy * proxy = NULL;
619
DBusGConnection * conn;
620
if( ( conn = dbus_g_bus_get( DBUS_BUS_SESSION, &err ) ) )
621
proxy = dbus_g_proxy_new_for_name ( conn, VALUE_SERVICE_NAME,
622
VALUE_SERVICE_OBJECT_PATH,
623
VALUE_SERVICE_INTERFACE );
625
g_message( "err: %s", err->message );
627
dbus_g_proxy_call( proxy, "PresentWindow", &err,
629
G_TYPE_BOOLEAN, &success,
632
g_message( "err: %s", err->message );
634
g_object_unref( proxy );
635
dbus_g_connection_unref( conn );
641
gtr_button_new_from_stock( const char * stock,
642
const char * mnemonic )
644
GtkWidget * image = gtk_image_new_from_stock( stock,
645
GTK_ICON_SIZE_BUTTON );
646
GtkWidget * button = gtk_button_new_with_mnemonic( mnemonic );
648
gtk_button_set_image( GTK_BUTTON( button ), image );
488
gtr_inhibit_hibernation( void )
657
gtr_timeout_add_seconds( guint seconds, GSourceFunc function, gpointer data )
490
guint inhibit_cookie = 0;
491
#ifdef HAVE_DBUS_GLIB
492
DBusGProxy * proxy = get_hibernation_inhibit_proxy( );
495
GError * error = NULL;
496
const char * application = _( "Transmission Bittorrent Client" );
497
const char * reason = _( "BitTorrent Activity" );
498
gboolean success = dbus_g_proxy_call( proxy, "Inhibit", &error,
499
G_TYPE_STRING, application,
500
G_TYPE_STRING, reason,
502
G_TYPE_UINT, &inhibit_cookie,
505
tr_inf( _( "Desktop hibernation disabled while Transmission is running" ) );
507
tr_err( _( "Couldn't disable desktop hibernation: %s" ), error->message );
508
g_error_free( error );
511
g_object_unref( G_OBJECT( proxy ) );
659
#if GLIB_CHECK_VERSION( 2,14,0 )
660
return g_timeout_add_seconds( seconds, function, data );
662
return g_timeout_add( seconds*1000, function, data );
514
return inhibit_cookie;
518
gtr_uninhibit_hibernation( guint inhibit_cookie )
667
gtr_widget_set_tooltip_text( GtkWidget * w, const char * tip )
520
#ifdef HAVE_DBUS_GLIB
521
DBusGProxy * proxy = get_hibernation_inhibit_proxy( );
524
GError * error = NULL;
525
gboolean success = dbus_g_proxy_call( proxy, "UnInhibit", &error,
526
G_TYPE_UINT, inhibit_cookie,
530
g_warning( "Couldn't uninhibit the system from suspending: %s.", error->message );
531
g_error_free( error );
534
g_object_unref( G_OBJECT( proxy ) );
669
#if GTK_CHECK_VERSION( 2,12,0 )
670
gtk_widget_set_tooltip_text( w, tip );
672
static GtkTooltips * tips = NULL;
674
tips = gtk_tooltips_new( );
675
gtk_tooltips_set_tip( tips, w, tip, NULL );