~ubuntu-branches/ubuntu/precise/transmission/precise

« back to all changes in this revision

Viewing changes to gtk/util.c

  • Committer: Bazaar Package Importer
  • Author(s): Leo Costela
  • Date: 2009-05-17 19:39:51 UTC
  • mto: (1.3.4 upstream) (2.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 36.
  • Revision ID: james.westby@ubuntu.com-20090517193951-k8x15sqoxzf7cuyx
ImportĀ upstreamĀ versionĀ 1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/******************************************************************************
2
 
 * $Id: util.c 6182 2008-06-13 21:12:49Z charles $
 
2
 * $Id: util.c 8283 2009-04-25 14:08:40Z charles $
3
3
 *
4
4
 * Copyright (c) 2005-2008 Transmission authors and contributors
5
5
 *
23
23
 *****************************************************************************/
24
24
 
25
25
#include <ctype.h> /* isxdigit() */
 
26
#include <errno.h>
26
27
#include <stdarg.h>
27
28
#include <stdlib.h> /* free() */
28
29
#include <string.h> /* strcmp() */
31
32
#include <glib/gi18n.h>
32
33
#include <glib/gstdio.h> /* g_unlink() */
33
34
#ifdef HAVE_GIO
34
 
#include <gio/gio.h> /* g_file_trash() */
 
35
 #include <gio/gio.h> /* g_file_trash() */
35
36
#endif
36
37
#ifdef HAVE_DBUS_GLIB
37
 
#include <dbus/dbus-glib.h>
 
38
 #include <dbus/dbus-glib.h>
38
39
#endif
39
40
 
40
41
#include <libevent/evhttp.h>
41
42
 
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 */
44
46
 
45
47
#include "conf.h"
 
48
#include "hig.h"
46
49
#include "tr-prefs.h"
47
50
#include "util.h"
48
51
 
49
 
int
50
 
tr_strcmp( const char * a, const char * b )
51
 
{
52
 
    if( a && b ) return strcmp( a, b );
53
 
    if( a ) return 1;
54
 
    if( b ) return -1;
55
 
    return 0;
56
 
}
57
 
 
58
52
char*
59
53
tr_strlratio( char * buf, double ratio, size_t buflen )
60
54
{
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 );
69
 
    else
70
 
        g_snprintf( buf, buflen, "%'.0f", ratio );
71
 
    return buf;
 
55
    return tr_strratio( buf, buflen, ratio, "\xE2\x88\x9E" );
72
56
}
73
57
 
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 )
77
61
 
78
62
char*
79
 
tr_strlsize( char * buf, guint64 size, size_t buflen )
 
63
tr_strlsize( char *  buf,
 
64
             guint64 size,
 
65
             size_t  buflen )
80
66
{
81
67
    if( !size )
82
68
        g_strlcpy( buf, _( "None" ), buflen );
83
 
#if GLIB_CHECK_VERSION(2,16,0)
84
 
    else{ 
 
69
#if GLIB_CHECK_VERSION( 2, 16, 0 )
 
70
    else
 
71
    {
85
72
        char * tmp = g_format_size_for_display( size );
86
73
        g_strlcpy( buf, tmp, buflen );
87
74
        g_free( tmp );
88
75
    }
89
76
#else
90
77
    else if( size < (guint64)KILOBYTE_FACTOR )
91
 
        g_snprintf( buf, buflen, ngettext("%'u byte", "%'u bytes", (guint)size), (guint)size );
92
 
    else {
 
78
        g_snprintf( buf, buflen,
 
79
                    ngettext( "%'u byte", "%'u bytes",
 
80
                              (guint)size ), (guint)size );
 
81
    else
 
82
    {
93
83
        gdouble displayed_size;
94
 
        if (size < (guint64)MEGABYTE_FACTOR) {
 
84
        if( size < (guint64)MEGABYTE_FACTOR )
 
85
        {
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 );
 
88
        }
 
89
        else if( size < (guint64)GIGABYTE_FACTOR )
 
90
        {
98
91
            displayed_size = (gdouble) size / MEGABYTE_FACTOR;
99
 
            g_snprintf( buf, buflen, _("%'.1f MB"), displayed_size );
100
 
        } else {
 
92
            g_snprintf( buf, buflen, _( "%'.1f MB" ), displayed_size );
 
93
        }
 
94
        else
 
95
        {
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 );
103
98
        }
104
99
    }
105
100
#endif
107
102
}
108
103
 
109
104
char*
110
 
tr_strlspeed( char * buf, double kb_sec, size_t buflen )
 
105
tr_strlspeed( char * buf,
 
106
              double kb_sec,
 
107
              size_t buflen )
111
108
{
112
109
    const double speed = kb_sec;
113
110
 
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 ) );
122
119
 
123
120
    return buf;
124
121
}
125
122
 
126
123
char*
127
 
tr_strltime( char * buf, int seconds, size_t buflen )
 
124
tr_strltime( char * buf,
 
125
             int    seconds,
 
126
             size_t buflen )
128
127
{
129
 
    int hours;
130
 
    int days;
 
128
    int  days, hours, minutes;
 
129
    char d[128], h[128], m[128], s[128];
131
130
 
132
131
    if( seconds < 0 )
133
132
        seconds = 0;
134
133
 
135
 
    if( seconds < 60 )
136
 
    {
137
 
        g_snprintf( buf, buflen, ngettext( "%'d second", "%'d seconds", (int)seconds ), (int) seconds );
138
 
        return buf;
139
 
    }
140
 
 
141
 
    if( seconds < ( 60 * 60 ) )
142
 
    {
143
 
        const int minutes = ( seconds + 30 ) / 60;
144
 
        g_snprintf( buf, buflen, ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
145
 
        return buf;
146
 
    }
147
 
 
148
 
    hours = seconds / ( 60 * 60 );
149
 
 
150
 
    if( seconds < ( 60 * 60 * 4 ) )
151
 
    {
152
 
        char h[64];
153
 
        char m[64];
154
 
 
155
 
        const int minutes = ( seconds - hours * 60 * 60 + 30 ) / 60;
156
 
 
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 );
160
 
        return buf;
161
 
    }
162
 
 
163
 
    if( hours < 24 )
164
 
    {
165
 
        g_snprintf( buf, buflen, ngettext( "%'d hour", "%'d hours", hours ), hours );
166
 
        return buf;
167
 
    }
168
 
 
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;
 
138
 
 
139
    g_snprintf( d, sizeof( d ), ngettext( "%'d day", "%'d days",
 
140
                                          days ), days );
 
141
    g_snprintf( h, sizeof( h ), ngettext( "%'d hour", "%'d hours",
 
142
                                          hours ), 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 );
 
147
 
 
148
    if( days )
 
149
    {
 
150
        if( days >= 4 || !hours )
 
151
        {
 
152
            g_strlcpy( buf, d, buflen );
 
153
        }
 
154
        else
 
155
        {
 
156
            g_snprintf( buf, buflen, "%s, %s", d, h );
 
157
        }
 
158
    }
 
159
    else if( hours )
 
160
    {
 
161
        if( hours >= 4 || !minutes )
 
162
        {
 
163
            g_strlcpy( buf, h, buflen );
 
164
        }
 
165
        else
 
166
        {
 
167
            g_snprintf( buf, buflen, "%s, %s", h, m );
 
168
        }
 
169
    }
 
170
    else if( minutes )
 
171
    {
 
172
        if( minutes >= 4 || !seconds )
 
173
        {
 
174
            g_strlcpy( buf, m, buflen );
 
175
        }
 
176
        else
 
177
        {
 
178
            g_snprintf( buf, buflen, "%s, %s", m, s );
 
179
        }
 
180
    }
 
181
    else
 
182
    {
 
183
        g_strlcpy( buf, s, buflen );
 
184
    }
 
185
 
171
186
    return buf;
172
187
}
173
188
 
174
 
 
175
189
char *
176
 
rfc822date (guint64 epoch_msec)
 
190
gtr_localtime( time_t time )
177
191
{
178
 
    const time_t secs = epoch_msec / 1000;
179
 
    const struct tm tm = *localtime (&secs);
180
 
    char buf[128];
181
 
    strftime( buf, sizeof(buf), "%a, %d %b %Y %T %Z", &tm );
 
192
    const struct tm tm = *localtime( &time );
 
193
    char            buf[256], *eoln;
 
194
 
 
195
    g_strlcpy( buf, asctime( &tm ), sizeof( buf ) );
 
196
    if( ( eoln = strchr( buf, '\n' ) ) )
 
197
        *eoln = '\0';
 
198
 
182
199
    return g_locale_to_utf8( buf, -1, NULL, NULL, NULL );
183
200
}
184
201
 
185
 
gboolean
186
 
mkdir_p( const char * path, mode_t mode )
187
 
{
188
 
#if GLIB_CHECK_VERSION( 2, 8, 0)
 
202
char *
 
203
gtr_localtime2( char * buf, time_t time, size_t buflen )
 
204
{
 
205
    char * tmp = gtr_localtime( time );
 
206
    g_strlcpy( buf, tmp, buflen );
 
207
    g_free( tmp );
 
208
    return buf;
 
209
}
 
210
 
 
211
int
 
212
mkdir_p( const char * path,
 
213
         mode_t       mode )
 
214
{
 
215
#if GLIB_CHECK_VERSION( 2, 8, 0 )
189
216
    return !g_mkdir_with_parents( path, mode );
190
217
#else
191
218
    return !tr_mkdirp( path, mode );
196
223
dupstrlist( GSList * l )
197
224
{
198
225
    GSList * ret = NULL;
199
 
    for( ; l!=NULL; l=l->next )
 
226
 
 
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 );
202
230
}
203
231
 
204
232
char *
205
 
joinstrlist(GSList *list, char *sep)
 
233
joinstrlist( GSList *list,
 
234
             char *  sep )
206
235
{
207
 
  GSList *l;
208
 
  GString *gstr = g_string_new (NULL);
209
 
  for (l=list; l!=NULL; l=l->next) {
210
 
    g_string_append (gstr, (char*)l->data);
211
 
    if (l->next != NULL)
212
 
      g_string_append (gstr, (sep));
213
 
  }
214
 
  return g_string_free (gstr, FALSE);
 
236
    GSList * l;
 
237
    GString *gstr = g_string_new ( NULL );
 
238
 
 
239
    for( l = list; l != NULL; l = l->next )
 
240
    {
 
241
        g_string_append ( gstr, (char*)l->data );
 
242
        if( l->next != NULL )
 
243
            g_string_append ( gstr, ( sep ) );
 
244
    }
 
245
    return g_string_free ( gstr, FALSE );
215
246
}
216
247
 
217
248
void
218
 
freestrlist(GSList *list)
 
249
freestrlist( GSList *list )
219
250
{
220
 
  g_slist_foreach (list, (GFunc)g_free, NULL);
221
 
  g_slist_free (list);
 
251
    g_slist_foreach ( list, (GFunc)g_free, NULL );
 
252
    g_slist_free ( list );
222
253
}
223
254
 
224
255
char *
225
256
decode_uri( const char * uri )
226
257
{
227
258
    gboolean in_query = FALSE;
228
 
    char * ret = g_new( char, strlen( uri ) + 1 );
229
 
    char * out = ret;
230
 
    for( ; uri && *uri; ) {
 
259
    char *   ret = g_new( char, strlen( uri ) + 1 );
 
260
    char *   out = ret;
 
261
 
 
262
    for( ; uri && *uri; )
 
263
    {
231
264
        char ch = *uri;
232
 
        if( ch=='?' )
 
265
        if( ch == '?' )
233
266
            in_query = TRUE;
234
 
        else if( ch=='+' && in_query )
 
267
        else if( ch == '+' && in_query )
235
268
            ch = ' ';
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] ) )
 
271
        {
238
272
            char buf[3] = { uri[1], uri[2], '\0' };
239
273
            ch = (char) g_ascii_strtoull( buf, NULL, 16 );
240
274
            uri += 2;
241
 
       }
 
275
        }
242
276
 
243
 
       ++uri;
244
 
       *out++ = ch;
 
277
        ++uri;
 
278
        *out++ = ch;
245
279
    }
246
280
 
247
281
    *out = '\0';
249
283
}
250
284
 
251
285
GSList *
252
 
checkfilenames( int argc, char **argv )
 
286
checkfilenames( int    argc,
 
287
                char **argv )
253
288
{
254
 
    int i;
 
289
    int      i;
255
290
    GSList * ret = NULL;
256
 
    char * pwd = g_get_current_dir( );
 
291
    char *   pwd = g_get_current_dir( );
257
292
 
258
 
    for( i=0; i<argc; ++i )
 
293
    for( i = 0; i < argc; ++i )
259
294
    {
260
295
        char * filename = g_path_is_absolute( argv[i] )
261
 
            ? g_strdup ( argv[i] )
262
 
            : g_build_filename( pwd, argv[i], NULL );
 
296
                          ? g_strdup ( argv[i] )
 
297
                          : g_build_filename( pwd, argv[i], NULL );
263
298
 
264
299
        if( g_file_test( filename, G_FILE_TEST_EXISTS ) )
265
300
            ret = g_slist_prepend( ret, filename );
271
306
    return g_slist_reverse( ret );
272
307
}
273
308
 
274
 
char *
275
 
getdownloaddir( void )
276
 
{
277
 
    static char * wd = NULL;
278
 
    char * dir = pref_string_get( PREF_KEY_DIR_DEFAULT );
279
 
    if ( dir == NULL ) {
280
 
        if( wd == NULL )
281
 
            wd = g_get_current_dir();
282
 
        dir = g_strdup( wd );
283
 
    }
284
 
    return dir;
285
 
}
286
 
 
287
309
static void
288
 
onErrorResponse(GtkWidget * dialog, int resp UNUSED, gpointer glist)
 
310
onErrorResponse( GtkWidget * dialog,
 
311
                 int resp    UNUSED,
 
312
                 gpointer    glist )
289
313
{
290
314
    GSList * list = glist;
 
315
 
291
316
    if( list )
292
317
    {
293
318
        callbackfunc_t func = list->data;
294
 
        gpointer user_data = list->next->data;
 
319
        gpointer       user_data = list->next->data;
295
320
        func( user_data );
296
321
        g_slist_free( list );
297
322
    }
300
325
}
301
326
 
302
327
static GtkWidget *
303
 
verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
304
 
              const char * format, va_list ap )
305
 
{
306
 
  GtkWidget *dialog;
307
 
  char *msg;
308
 
  GSList *funcdata = NULL;
309
 
 
310
 
  msg = g_strdup_vprintf(format, ap);
311
 
 
312
 
  if(NULL == wind)
313
 
    dialog = gtk_message_dialog_new(
314
 
      NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
315
 
  else
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);
319
 
 
320
 
  if( func ) {
321
 
    funcdata = g_slist_append( funcdata, (gpointer)func );
322
 
    funcdata = g_slist_append( funcdata, data );
323
 
  }
324
 
  g_signal_connect(dialog, "response", G_CALLBACK(onErrorResponse), funcdata);
325
 
  g_free(msg);
326
 
 
327
 
  return dialog;
328
 
}
329
 
 
330
 
void
331
 
errmsg( GtkWindow * wind, const char * format, ... )
 
328
verrmsg_full( GtkWindow *    wind,
 
329
              callbackfunc_t func,
 
330
              void *         data,
 
331
              const char *   format,
 
332
              va_list        ap )
 
333
{
 
334
    GtkWidget *dialog;
 
335
    char *     msg;
 
336
    GSList *   funcdata = NULL;
 
337
 
 
338
    msg = g_strdup_vprintf( format, ap );
 
339
 
 
340
    if( NULL == wind )
 
341
        dialog = gtk_message_dialog_new(
 
342
            NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg );
 
343
    else
 
344
        dialog = gtk_message_dialog_new(
 
345
            wind,
 
346
            GTK_DIALOG_MODAL |
 
347
            GTK_DIALOG_DESTROY_WITH_PARENT,
 
348
            GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 
349
            "%s", msg );
 
350
 
 
351
    if( func )
 
352
    {
 
353
        funcdata = g_slist_append( funcdata, (gpointer)func );
 
354
        funcdata = g_slist_append( funcdata, data );
 
355
    }
 
356
    g_signal_connect( dialog, "response", G_CALLBACK(
 
357
                          onErrorResponse ), funcdata );
 
358
    g_free( msg );
 
359
 
 
360
    return dialog;
 
361
}
 
362
 
 
363
void
 
364
addTorrentErrorDialog( GtkWidget *  child,
 
365
                       int          err,
 
366
                       const char * filename )
 
367
{
 
368
    GtkWidget *  w;
 
369
    GtkWidget *  win;
 
370
    const char * fmt;
 
371
    char *       secondary;
 
372
 
 
373
    switch( err )
 
374
    {
 
375
        case TR_EINVALID:
 
376
            fmt = _( "The torrent file \"%s\" contains invalid data." );
 
377
            break;
 
378
 
 
379
        case TR_EDUPLICATE:
 
380
            fmt = _( "The torrent file \"%s\" is already in use." ); break;
 
381
 
 
382
        default:
 
383
            fmt = _(
 
384
                "The torrent file \"%s\" encountered an unknown error." );
 
385
            break;
 
386
    }
 
387
    secondary = g_strdup_printf( fmt, filename );
 
388
    win = ( !child || GTK_IS_WINDOW( child ) )
 
389
          ? 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,
 
394
                               GTK_MESSAGE_ERROR,
 
395
                               GTK_BUTTONS_CLOSE,
 
396
                               _( "Error opening torrent" ) );
 
397
    gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ),
 
398
                                              "%s", secondary );
 
399
    g_signal_connect_swapped( w, "response",
 
400
                              G_CALLBACK( gtk_widget_destroy ), w );
 
401
    gtk_widget_show_all( w );
 
402
    g_free( secondary );
 
403
}
 
404
 
 
405
void
 
406
errmsg( GtkWindow *  wind,
 
407
        const char * format,
 
408
        ... )
332
409
{
333
410
    GtkWidget * dialog;
334
411
    va_list     ap;
349
426
}
350
427
 
351
428
GtkWidget *
352
 
errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
353
 
             const char * format, ... )
 
429
errmsg_full( GtkWindow *    wind,
 
430
             callbackfunc_t func,
 
431
             void *         data,
 
432
             const char *   format,
 
433
             ... )
354
434
{
355
435
    GtkWidget * dialog;
356
436
    va_list     ap;
362
442
    return dialog;
363
443
}
364
444
 
365
 
typedef void (PopupFunc)(GtkWidget*, GdkEventButton*); 
 
445
typedef void ( PopupFunc )( GtkWidget*, GdkEventButton* );
366
446
 
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. */
369
449
 
370
450
gboolean
371
 
on_tree_view_button_pressed (GtkWidget       * view,
372
 
                             GdkEventButton  * event,
373
 
                             gpointer          func)
374
 
{
375
 
  GtkTreeView * tv = GTK_TREE_VIEW( view );
376
 
 
377
 
  if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3)
378
 
  {
379
 
    GtkTreeSelection * selection = gtk_tree_view_get_selection(tv);
380
 
    GtkTreePath *path;
381
 
    if (gtk_tree_view_get_path_at_pos (tv,
382
 
                                       (gint) event->x,
383
 
                                       (gint) event->y,
384
 
                                       &path, NULL, NULL, NULL))
385
 
    {
386
 
      if (!gtk_tree_selection_path_is_selected (selection, path))
387
 
      {
388
 
        gtk_tree_selection_unselect_all (selection);
389
 
        gtk_tree_selection_select_path (selection, path);
390
 
      }
391
 
      gtk_tree_path_free(path);
392
 
    }
393
 
   
394
 
    ((PopupFunc*)func)(view, event);
395
 
 
396
 
    return TRUE;
397
 
  }
398
 
 
399
 
  return FALSE;
 
451
on_tree_view_button_pressed( GtkWidget *      view,
 
452
                             GdkEventButton * event,
 
453
                             gpointer         func )
 
454
{
 
455
    GtkTreeView * tv = GTK_TREE_VIEW( view );
 
456
 
 
457
    if( event->type == GDK_BUTTON_PRESS  &&  event->button == 3 )
 
458
    {
 
459
        GtkTreeSelection * selection = gtk_tree_view_get_selection( tv );
 
460
        GtkTreePath *      path;
 
461
        if( gtk_tree_view_get_path_at_pos ( tv,
 
462
                                            (gint) event->x,
 
463
                                            (gint) event->y,
 
464
                                            &path, NULL, NULL, NULL ) )
 
465
        {
 
466
            if( !gtk_tree_selection_path_is_selected ( selection, path ) )
 
467
            {
 
468
                gtk_tree_selection_unselect_all ( selection );
 
469
                gtk_tree_selection_select_path ( selection, path );
 
470
            }
 
471
            gtk_tree_path_free( path );
 
472
        }
 
473
 
 
474
        ( (PopupFunc*)func )( view, event );
 
475
 
 
476
        return TRUE;
 
477
    }
 
478
 
 
479
    return FALSE;
 
480
}
 
481
 
 
482
/* if the user clicked in an empty area of the list,
 
483
 * clear all the selections. */
 
484
gboolean
 
485
on_tree_view_button_released( GtkWidget *      view,
 
486
                              GdkEventButton * event,
 
487
                              gpointer         unused UNUSED )
 
488
{
 
489
    GtkTreeView * tv = GTK_TREE_VIEW( view );
 
490
 
 
491
    if( !gtk_tree_view_get_path_at_pos ( tv,
 
492
                                         (gint) event->x,
 
493
                                         (gint) event->y,
 
494
                                         NULL, NULL, NULL, NULL ) )
 
495
    {
 
496
        GtkTreeSelection * selection = gtk_tree_view_get_selection( tv );
 
497
        gtk_tree_selection_unselect_all ( selection );
 
498
        return TRUE;
 
499
    }
 
500
 
 
501
    return FALSE;
400
502
}
401
503
 
402
504
gpointer
403
505
tr_object_ref_sink( gpointer object )
404
506
{
405
 
#if GLIB_CHECK_VERSION(2,10,0)
 
507
#if GLIB_CHECK_VERSION( 2, 10, 0 )
406
508
    g_object_ref_sink( object );
407
509
#else
408
510
    g_object_ref( object );
411
513
    return object;
412
514
}
413
515
 
414
 
void
415
 
tr_file_trash_or_unlink( const char * filename )
 
516
int
 
517
tr_file_trash_or_remove( const char * filename )
416
518
{
417
519
    if( filename && *filename )
418
520
    {
419
521
        gboolean trashed = FALSE;
420
522
#ifdef HAVE_GIO
421
523
        GError * err = NULL;
422
 
        GFile * file = g_file_new_for_path( filename );
 
524
        GFile *  file = g_file_new_for_path( filename );
423
525
        trashed = g_file_trash( file, NULL, &err );
 
526
        if( err )
 
527
            g_message( "Unable to trash file \"%s\": %s", filename, err->message );
 
528
        g_clear_error( &err );
424
529
        g_object_unref( G_OBJECT( file ) );
425
 
#endif 
426
 
        if( !trashed )
427
 
            g_unlink( filename );
 
530
#endif
 
531
 
 
532
        if( !trashed && g_remove( filename ) )
 
533
        {
 
534
            const int err = errno;
 
535
            g_message( "Unable to remove file \"%s\": %s", filename, g_strerror( err ) );
 
536
        }
428
537
    }
 
538
 
 
539
    return 0;
429
540
}
430
541
 
431
542
char*
432
543
gtr_get_help_url( void )
433
544
{
434
545
    const char * fmt = "http://www.transmissionbt.com/help/gtk/%d.%dx";
435
 
    int major, minor;
 
546
    int          major, minor;
 
547
 
436
548
    sscanf( SHORT_VERSION_STRING, "%d.%d", &major, &minor );
437
 
    return g_strdup_printf( fmt, major, minor/10 );
 
549
    return g_strdup_printf( fmt, major, minor / 10 );
438
550
}
439
551
 
440
552
void
447
559
        if( !opened )
448
560
        {
449
561
            GFile * file = g_file_new_for_path( path );
450
 
            char * uri = g_file_get_uri( file );
 
562
            char *  uri = g_file_get_uri( file );
451
563
            opened = g_app_info_launch_default_for_uri( uri, NULL, NULL );
452
564
            g_free( uri );
453
565
            g_object_unref( G_OBJECT( file ) );
455
567
#endif
456
568
        if( !opened )
457
569
        {
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 );
461
573
        }
462
574
    }
463
575
}
464
576
 
465
 
#ifdef HAVE_DBUS_GLIB
466
 
static DBusGProxy*
467
 
get_hibernation_inhibit_proxy( void )
468
 
{
469
 
    GError * error = NULL;
470
 
    DBusGConnection * conn;
471
 
 
472
 
    conn = dbus_g_bus_get( DBUS_BUS_SESSION, &error );
473
 
    if( error )
474
 
    {
475
 
        g_warning ("DBUS cannot connect : %s", error->message);
476
 
        g_error_free (error);
477
 
        return NULL;
478
 
    }
479
 
 
480
 
    return dbus_g_proxy_new_for_name (conn,
481
 
               "org.freedesktop.PowerManagement",
482
 
               "/org/freedesktop/PowerManagement/Inhibit",
483
 
               "org.freedesktop.PowerManagement.Inhibit" );
484
 
}
485
 
#endif
 
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"
 
580
 
 
581
gboolean
 
582
gtr_dbus_add_torrent( const char * filename )
 
583
{
 
584
    static gboolean   success = FALSE;
 
585
 
 
586
#ifdef HAVE_DBUS_GLIB
 
587
    DBusGProxy *      proxy = NULL;
 
588
    GError *          err = 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 );
 
594
    else if( err )
 
595
        g_message( "err: %s", err->message );
 
596
    if( proxy )
 
597
        dbus_g_proxy_call( proxy, "AddFile", &err,
 
598
                           G_TYPE_STRING, filename,
 
599
                           G_TYPE_INVALID,
 
600
                           G_TYPE_BOOLEAN, &success,
 
601
                           G_TYPE_INVALID );
 
602
    if( err )
 
603
        g_message( "err: %s", err->message );
 
604
 
 
605
    g_object_unref( proxy );
 
606
    dbus_g_connection_unref( conn );
 
607
#endif
 
608
    return success;
 
609
}
 
610
 
 
611
gboolean
 
612
gtr_dbus_present_window( void )
 
613
{
 
614
    static gboolean   success = FALSE;
 
615
 
 
616
#ifdef HAVE_DBUS_GLIB
 
617
    DBusGProxy *      proxy = NULL;
 
618
    GError *          err = 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 );
 
624
    else if( err )
 
625
        g_message( "err: %s", err->message );
 
626
    if( proxy )
 
627
        dbus_g_proxy_call( proxy, "PresentWindow", &err,
 
628
                           G_TYPE_INVALID,
 
629
                           G_TYPE_BOOLEAN, &success,
 
630
                           G_TYPE_INVALID );
 
631
    if( err )
 
632
        g_message( "err: %s", err->message );
 
633
 
 
634
    g_object_unref( proxy );
 
635
    dbus_g_connection_unref( conn );
 
636
#endif
 
637
    return success;
 
638
}
 
639
 
 
640
GtkWidget *
 
641
gtr_button_new_from_stock( const char * stock,
 
642
                           const char * mnemonic )
 
643
{
 
644
    GtkWidget * image = gtk_image_new_from_stock( stock,
 
645
                                                  GTK_ICON_SIZE_BUTTON );
 
646
    GtkWidget * button = gtk_button_new_with_mnemonic( mnemonic );
 
647
 
 
648
    gtk_button_set_image( GTK_BUTTON( button ), image );
 
649
    return button;
 
650
}
 
651
 
 
652
/***
 
653
****
 
654
***/
486
655
 
487
656
guint
488
 
gtr_inhibit_hibernation( void )
 
657
gtr_timeout_add_seconds( guint seconds, GSourceFunc function, gpointer data )
489
658
{
490
 
    guint inhibit_cookie = 0;
491
 
#ifdef HAVE_DBUS_GLIB
492
 
    DBusGProxy * proxy = get_hibernation_inhibit_proxy( );
493
 
    if( proxy )
494
 
    {
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,
501
 
                                              G_TYPE_INVALID,
502
 
                                              G_TYPE_UINT, &inhibit_cookie,
503
 
                                              G_TYPE_INVALID );
504
 
        if( success )
505
 
            tr_inf( _( "Desktop hibernation disabled while Transmission is running" ) );
506
 
        else {
507
 
            tr_err( _( "Couldn't disable desktop hibernation: %s" ), error->message );
508
 
            g_error_free( error );
509
 
        }
510
 
 
511
 
        g_object_unref( G_OBJECT( proxy ) );
512
 
    }
 
659
#if GLIB_CHECK_VERSION( 2,14,0 )
 
660
    return g_timeout_add_seconds( seconds, function, data );
 
661
#else
 
662
    return g_timeout_add( seconds*1000, function, data );
513
663
#endif
514
 
    return inhibit_cookie;
515
664
}
516
665
 
517
666
void
518
 
gtr_uninhibit_hibernation( guint inhibit_cookie )
 
667
gtr_widget_set_tooltip_text( GtkWidget * w, const char * tip )
519
668
{
520
 
#ifdef HAVE_DBUS_GLIB
521
 
    DBusGProxy * proxy = get_hibernation_inhibit_proxy( );
522
 
    if( proxy )
523
 
    {
524
 
        GError * error = NULL;
525
 
        gboolean success = dbus_g_proxy_call( proxy, "UnInhibit", &error,
526
 
                                              G_TYPE_UINT, inhibit_cookie,
527
 
                                              G_TYPE_INVALID,
528
 
                                              G_TYPE_INVALID );
529
 
        if( !success ) {
530
 
            g_warning( "Couldn't uninhibit the system from suspending: %s.", error->message );
531
 
            g_error_free( error );
532
 
        }
533
 
 
534
 
        g_object_unref( G_OBJECT( proxy ) );
535
 
    }
 
669
#if GTK_CHECK_VERSION( 2,12,0 )
 
670
    gtk_widget_set_tooltip_text( w, tip );
 
671
#else
 
672
    static GtkTooltips * tips = NULL;
 
673
    if( tips == NULL )
 
674
        tips = gtk_tooltips_new( );
 
675
    gtk_tooltips_set_tip( tips, w, tip, NULL );
536
676
#endif
537
677
}