142
167
if( response == GTK_RESPONSE_CLOSE )
143
gtk_widget_destroy( GTK_WIDGET(dialog) );
168
gtk_widget_destroy( GTK_WIDGET( dialog ) );
147
toggled_cb( GtkToggleButton * w, gpointer core )
172
toggled_cb( GtkToggleButton * w,
149
const char * key = g_object_get_data( G_OBJECT(w), PREF_KEY );
175
const char * key = g_object_get_data( G_OBJECT( w ), PREF_KEY );
150
176
const gboolean flag = gtk_toggle_button_get_active( w );
151
tr_core_set_pref_bool( TR_CORE(core), key, flag );
178
tr_core_set_pref_bool( TR_CORE( core ), key, flag );
154
181
static GtkWidget*
155
new_check_button( const char * mnemonic, const char * key, gpointer core )
182
new_check_button( const char * mnemonic,
157
186
GtkWidget * w = gtk_check_button_new_with_mnemonic( mnemonic );
158
g_object_set_data_full( G_OBJECT(w), PREF_KEY, g_strdup(key), g_free );
159
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w), pref_flag_get(key) );
160
g_signal_connect( w, "toggled", G_CALLBACK(toggled_cb), core );
188
g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup(
190
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ),
191
pref_flag_get( key ) );
192
g_signal_connect( w, "toggled", G_CALLBACK( toggled_cb ), core );
165
spun_cb( GtkSpinButton * w, gpointer core )
167
const char * key = g_object_get_data( G_OBJECT(w), PREF_KEY );
168
const int value = gtk_spin_button_get_value_as_int( w );
169
tr_core_set_pref_int( TR_CORE(core), key, value );
196
#define IDLE_DATA "idle-data"
198
struct spin_idle_data
201
GTimer * last_change;
205
spin_idle_data_free( gpointer gdata )
207
struct spin_idle_data * data = gdata;
209
g_timer_destroy( data->last_change );
214
spun_cb_idle( gpointer spin )
216
gboolean keep_waiting = TRUE;
217
GObject * o = G_OBJECT( spin );
218
struct spin_idle_data * data = g_object_get_data( o, IDLE_DATA );
220
/* has the user stopped making changes? */
221
if( g_timer_elapsed( data->last_change, NULL ) > 0.33f )
223
/* update the core */
224
const char * key = g_object_get_data( o, PREF_KEY );
225
const int value = gtk_spin_button_get_value_as_int(
226
GTK_SPIN_BUTTON( spin ) );
227
tr_core_set_pref_int( TR_CORE( data->core ), key, value );
230
g_object_set_data( o, IDLE_DATA, NULL );
231
keep_waiting = FALSE;
232
g_object_unref( G_OBJECT( o ) );
239
spun_cb( GtkSpinButton * w,
242
/* user may be spinning through many values, so let's hold off
243
for a moment to keep from flooding the core with changes */
244
GObject * o = G_OBJECT( w );
245
struct spin_idle_data * data = g_object_get_data( o, IDLE_DATA );
249
data = g_new( struct spin_idle_data, 1 );
251
data->last_change = g_timer_new( );
252
g_object_set_data_full( o, IDLE_DATA, data, spin_idle_data_free );
253
g_object_ref( G_OBJECT( o ) );
254
g_timeout_add( 100, spun_cb_idle, w );
256
g_timer_start( data->last_change );
172
259
static GtkWidget*
173
new_spin_button( const char * key, gpointer core, int low, int high, int step )
260
new_spin_button( const char * key,
175
266
GtkWidget * w = gtk_spin_button_new_with_range( low, high, step );
176
g_object_set_data_full( G_OBJECT(w), PREF_KEY, g_strdup(key), g_free );
177
gtk_spin_button_set_digits( GTK_SPIN_BUTTON(w), 0 );
178
gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), pref_int_get(key) );
179
g_signal_connect( w, "value-changed", G_CALLBACK(spun_cb), core );
268
g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup(
270
gtk_spin_button_set_digits( GTK_SPIN_BUTTON( w ), 0 );
271
gtk_spin_button_set_value( GTK_SPIN_BUTTON( w ), pref_int_get( key ) );
272
g_signal_connect( w, "value-changed", G_CALLBACK( spun_cb ), core );
184
entry_changed_cb( GtkEntry * w, gpointer core )
277
entry_changed_cb( GtkEntry * w,
186
280
const char * key = g_object_get_data( G_OBJECT( w ), PREF_KEY );
187
281
const char * value = gtk_entry_get_text( w );
188
283
tr_core_set_pref( TR_CORE( core ), key, value );
191
286
static GtkWidget*
192
new_entry( const char * key, gpointer core )
287
new_entry( const char * key,
194
GtkWidget * w = gtk_entry_new( );
290
GtkWidget * w = gtk_entry_new( );
195
291
const char * value = pref_string_get( key );
197
294
gtk_entry_set_text( GTK_ENTRY( w ), value );
198
g_object_set_data_full( G_OBJECT(w), PREF_KEY, g_strdup(key), g_free );
199
g_signal_connect( w, "changed", G_CALLBACK(entry_changed_cb), core );
295
g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup(
297
g_signal_connect( w, "changed", G_CALLBACK( entry_changed_cb ), core );
204
chosen_cb( GtkFileChooser * w, gpointer core )
302
chosen_cb( GtkFileChooser * w,
206
const char * key = g_object_get_data( G_OBJECT(w), PREF_KEY );
207
char * value = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(w) );
208
tr_core_set_pref( TR_CORE(core), key, value );
305
const char * key = g_object_get_data( G_OBJECT( w ), PREF_KEY );
306
char * value = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( w ) );
308
tr_core_set_pref( TR_CORE( core ), key, value );
212
312
static GtkWidget*
213
new_path_chooser_button( const char * key, gpointer core )
313
new_path_chooser_button( const char * key,
215
GtkWidget * w = gtk_file_chooser_button_new( NULL,
216
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
316
GtkWidget * w = gtk_file_chooser_button_new(
318
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
217
319
const char * path = pref_string_get( key );
218
g_object_set_data_full( G_OBJECT(w), PREF_KEY, g_strdup(key), g_free );
219
g_signal_connect( w, "selection-changed", G_CALLBACK(chosen_cb), core );
220
gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(w), path );
321
g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup(
323
g_signal_connect( w, "selection-changed", G_CALLBACK( chosen_cb ), core );
324
gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), path );
225
target_cb( GtkWidget * tb, gpointer target )
329
target_cb( GtkWidget * tb,
227
332
const gboolean b = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( tb ) );
228
gtk_widget_set_sensitive( GTK_WIDGET(target), b );
231
struct test_port_data
238
testing_port_done( tr_handle * handle UNUSED,
239
long response_code UNUSED,
240
const void * response,
244
struct test_port_data * data = gdata;
247
const int isOpen = response_len && *(char*)response=='1';
248
gtk_label_set_markup( GTK_LABEL( data->label ), isOpen
249
? _("Port is <b>open</b>")
250
: _("Port is <b>closed</b>") );
255
testing_port_begin( gpointer gdata )
257
struct test_port_data * data = gdata;
260
GtkSpinButton * spin = g_object_get_data( G_OBJECT( data->label ), "tr-port-spin" );
261
tr_handle * handle = g_object_get_data( G_OBJECT( data->label ), "handle" );
262
const int port = gtk_spin_button_get_value_as_int( spin );
264
g_snprintf( url, sizeof(url), "http://portcheck.transmissionbt.com/%d", port );
265
tr_webRun( handle, url, NULL, testing_port_done, data );
271
testing_port_cb( GtkWidget * unused UNUSED, gpointer l )
273
struct test_port_data * data;
275
gtk_label_set_markup( GTK_LABEL( l ), _( "<i>Testing port...</i>" ) );
277
/* wait three seconds to give the port forwarding time to kick in */
278
data = g_new0( struct test_port_data, 1 );
280
data->alive = g_object_get_data( G_OBJECT( l ), "alive" );
281
g_timeout_add( 3000, testing_port_begin, data );
285
dialogDestroyed( gpointer alive, GObject * dialog UNUSED )
287
*(gboolean*)alive = FALSE;
334
gtk_widget_set_sensitive( GTK_WIDGET( target ), b );
290
341
static GtkWidget*
291
342
torrentPage( GObject * core )
301
353
t = hig_workarea_create( );
302
354
hig_workarea_add_section_title( t, &row, _( "Adding Torrents" ) );
305
s = _( "Automatically _add torrents from:" );
306
l = new_check_button( s, PREF_KEY_DIR_WATCH_ENABLED, core );
307
w = new_path_chooser_button( PREF_KEY_DIR_WATCH, core );
308
gtk_widget_set_sensitive( GTK_WIDGET(w), pref_flag_get( PREF_KEY_DIR_WATCH_ENABLED ) );
309
g_signal_connect( l, "toggled", G_CALLBACK(target_cb), w );
310
hig_workarea_add_row_w( t, &row, l, w, NULL );
357
s = _( "Automatically _add torrents from:" );
358
l = new_check_button( s, PREF_KEY_DIR_WATCH_ENABLED, core );
359
w = new_path_chooser_button( PREF_KEY_DIR_WATCH, core );
360
gtk_widget_set_sensitive( GTK_WIDGET( w ),
361
pref_flag_get( PREF_KEY_DIR_WATCH_ENABLED ) );
362
g_signal_connect( l, "toggled", G_CALLBACK( target_cb ), w );
363
hig_workarea_add_row_w( t, &row, l, w, NULL );
313
s = _( "Display _options dialog" );
314
w = new_check_button( s, PREF_KEY_OPTIONS_PROMPT, core );
315
hig_workarea_add_wide_control( t, &row, w );
317
s = _( "_Start when added" );
318
w = new_check_button( s, PREF_KEY_START, core );
319
hig_workarea_add_wide_control( t, &row, w );
321
s = _( "Mo_ve source files to Trash" );
322
w = new_check_button( s, PREF_KEY_TRASH_ORIGINAL, core );
323
hig_workarea_add_wide_control( t, &row, w );
325
w = new_path_chooser_button( PREF_KEY_DOWNLOAD_DIR, core );
326
hig_workarea_add_row( t, &row, _( "_Destination folder:" ), w, NULL );
328
hig_workarea_finish( t, &row );
366
s = _( "Display _options dialog" );
367
w = new_check_button( s, PREF_KEY_OPTIONS_PROMPT, core );
368
hig_workarea_add_wide_control( t, &row, w );
370
s = _( "_Start when added" );
371
w = new_check_button( s, PREF_KEY_START, core );
372
hig_workarea_add_wide_control( t, &row, w );
374
s = _( "Mo_ve source files to Trash" );
375
w = new_check_button( s, PREF_KEY_TRASH_ORIGINAL, core );
376
hig_workarea_add_wide_control( t, &row, w );
378
w = new_path_chooser_button( PREF_KEY_DOWNLOAD_DIR, core );
379
hig_workarea_add_row( t, &row, _( "_Destination folder:" ), w, NULL );
381
hig_workarea_finish( t, &row );
390
desktopPage( GObject * core )
397
t = hig_workarea_create( );
398
hig_workarea_add_section_title( t, &row, _( "Options" ) );
400
s = _( "Inhibit desktop _hibernation when torrents are active" );
401
w = new_check_button( s, PREF_KEY_INHIBIT_HIBERNATION, core );
402
hig_workarea_add_wide_control( t, &row, w );
404
s = _( "Show _icon in the desktop Notification Area" );
405
w = new_check_button( s, PREF_KEY_SHOW_TRAY_ICON, core );
406
hig_workarea_add_wide_control( t, &row, w );
408
hig_workarea_finish( t, &row );
336
416
struct blocklist_data
346
updateBlocklistText( GtkWidget * w, TrCore * core )
427
updateBlocklistText( GtkWidget * w,
348
const int n = tr_blocklistGetRuleCount( tr_core_handle( core ) );
430
const int n = tr_blocklistGetRuleCount( tr_core_session( core ) );
350
433
g_snprintf( buf, sizeof( buf ),
351
ngettext( "Ignore the %'d _blocklisted peer",
352
"Ignore the %'d _blocklisted peers", n ), n );
434
ngettext( "Enable _blocklist (contains %'d rule)",
435
"Enable _blocklist (contains %'d rules)", n ), n );
353
436
gtk_button_set_label( GTK_BUTTON( w ), buf );
356
updateBlocklistTextFromData( gpointer gdata )
358
struct blocklist_data * data = gdata;
359
updateBlocklistText( data->check, data->core );
364
blocklistDialogSetSecondary( gpointer gdata )
366
struct blocklist_data * data = gdata;
367
GtkMessageDialog * md = GTK_MESSAGE_DIALOG( data->dialog );
368
gtk_message_dialog_format_secondary_text( md, data->secondary );
373
blocklistDialogAllowClose( gpointer dialog )
375
GtkDialog * d = GTK_DIALOG( dialog );
376
gtk_dialog_set_response_sensitive( GTK_DIALOG( d ), GTK_RESPONSE_CANCEL, FALSE );
377
gtk_dialog_set_response_sensitive( GTK_DIALOG( d ), GTK_RESPONSE_CLOSE, TRUE );
382
got_blocklist( tr_handle * handle UNUSED,
383
long response_code UNUSED,
384
const void * response,
388
struct blocklist_data * data = gdata;
389
const char * text = response;
390
int size = response_len;
392
gchar * filename = NULL;
393
gchar * filename2 = NULL;
397
if( !data->abortFlag && ( !text || !size ) )
400
g_snprintf( data->secondary, sizeof( data->secondary ),
401
_( "Unable to get blocklist." ) );
402
g_message( data->secondary );
403
g_idle_add( blocklistDialogSetSecondary, data );
406
if( ok && !data->abortFlag )
409
fd = g_file_open_tmp( "transmission-blockfile-XXXXXX", &filename, &err );
411
g_snprintf( data->secondary, sizeof( data->secondary ),
412
_( "Unable to get blocklist: %s" ), err->message );
413
g_warning( data->secondary );
414
g_idle_add( blocklistDialogSetSecondary, data );
415
g_clear_error( &err );
418
write( fd, text, size );
422
if( ok && !data->abortFlag )
425
filename2 = g_strdup_printf( "%s.txt", filename );
426
g_snprintf( data->secondary, sizeof( data->secondary ),
427
_( "Uncompressing blocklist..." ) );
428
g_idle_add( blocklistDialogSetSecondary, data );
429
cmd = g_strdup_printf( "zcat %s > %s ", filename, filename2 );
434
if( ok && !data->abortFlag )
436
g_snprintf( data->secondary, sizeof( data->secondary ),
437
_( "Parsing blocklist..." ) );
438
g_idle_add( blocklistDialogSetSecondary, data );
439
rules = tr_blocklistSetContent( tr_core_handle( data->core ), filename2 );
441
if( ok && !data->abortFlag )
443
g_snprintf( data->secondary, sizeof( data->secondary ),
444
_( "Blocklist updated with %'d entries" ), rules );
445
g_idle_add( blocklistDialogSetSecondary, data );
446
g_idle_add( blocklistDialogAllowClose, data->dialog );
447
g_idle_add( updateBlocklistTextFromData, data );
450
/* g_free( data ); */
462
onUpdateBlocklistResponseCB( GtkDialog * dialog, int response, gpointer vdata )
464
struct blocklist_data * data = vdata;
466
if( response == GTK_RESPONSE_CANCEL )
470
gtk_widget_destroy( GTK_WIDGET( dialog ) );
474
onUpdateBlocklistCB( GtkButton * w, gpointer gdata )
477
struct blocklist_data * data = gdata;
478
tr_handle * handle = g_object_get_data( G_OBJECT( w ), "handle" );
479
const char * url = "http://download.m0k.org/transmission/files/level1.gz";
481
d = gtk_message_dialog_new( GTK_WINDOW( gtk_widget_get_toplevel( GTK_WIDGET( w ) ) ),
482
GTK_DIALOG_DESTROY_WITH_PARENT,
485
_( "Updating Blocklist" ) );
486
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( d ),
487
_( "Retrieving blocklist..." ) );
440
onBlocklistDialogResponse( GtkDialog * d,
444
struct blocklist_data * data = gdata;
446
g_signal_handler_disconnect( data->core, data->id );
447
gtk_widget_destroy( GTK_WIDGET( d ) );
451
onBlocklistStatus( TrCore * core UNUSED,
456
struct blocklist_data * data = gdata;
458
gdk_threads_enter( );
459
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( data-> dialog ),
461
gtk_dialog_set_response_sensitive( GTK_DIALOG( data->dialog ),
462
GTK_RESPONSE_CANCEL, !isDone );
463
gtk_dialog_set_response_sensitive( GTK_DIALOG( data->dialog ),
464
GTK_RESPONSE_CLOSE, isDone );
466
updateBlocklistText( data->check, core );
467
gdk_threads_leave( );
471
onUpdateBlocklistCB( GtkButton * w,
475
struct blocklist_data * data = gdata;
478
gtk_message_dialog_new( GTK_WINDOW( gtk_widget_get_toplevel(
481
GTK_DIALOG_DESTROY_WITH_PARENT,
484
_( "Updating Blocklist" ) );
488
g_signal_connect( data->core, "blocklist-status", G_CALLBACK(
489
onBlocklistStatus ), data );
488
491
gtk_dialog_add_buttons( GTK_DIALOG( d ),
489
492
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
490
493
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
492
gtk_dialog_set_response_sensitive( GTK_DIALOG( d ), GTK_RESPONSE_CLOSE, FALSE );
496
g_signal_connect( d, "response", G_CALLBACK(onUpdateBlocklistResponseCB), data );
495
gtk_dialog_set_response_sensitive( GTK_DIALOG(
496
d ), GTK_RESPONSE_CLOSE, FALSE );
498
g_signal_connect( d, "response", G_CALLBACK(
499
onBlocklistDialogResponse ), data );
497
500
gtk_widget_show( d );
499
tr_webRun( handle, url, NULL, got_blocklist, data );
502
gtr_blocklist_update( data->core );
503
onEncryptionToggled( GtkToggleButton * w, gpointer core )
506
onEncryptionToggled( GtkToggleButton * w,
505
509
const int val = gtk_toggle_button_get_active( w )
506
? TR_ENCRYPTION_REQUIRED
507
: TR_ENCRYPTION_PREFERRED;
510
? TR_ENCRYPTION_REQUIRED
511
: TR_ENCRYPTION_PREFERRED;
508
513
tr_core_set_pref_int( TR_CORE( core ), PREF_KEY_ENCRYPTION, val );
511
516
static GtkWidget*
512
peerPage( GObject * core, gboolean * alive )
517
peerPage( GObject * core )
522
525
struct blocklist_data * data;
527
data = g_new0( struct blocklist_data, 1 );
528
data->core = TR_CORE( core );
524
530
t = hig_workarea_create( );
525
hig_workarea_add_section_title (t, &row, _("Options"));
527
w = new_check_button( "", PREF_KEY_BLOCKLIST_ENABLED, core );
528
updateBlocklistText( w, TR_CORE( core ) );
529
h = gtk_hbox_new( FALSE, GUI_PAD_BIG );
530
gtk_box_pack_start_defaults( GTK_BOX(h), w );
531
b = gtk_button_new_with_mnemonic( _( "_Update Blocklist" ) );
533
data = g_new0( struct blocklist_data, 1 );
534
data->core = TR_CORE( core );
537
g_object_set_data( G_OBJECT( b ), "handle", tr_core_handle( TR_CORE( core ) ) );
538
g_signal_connect( b, "clicked", G_CALLBACK(onUpdateBlocklistCB), data );
539
gtk_box_pack_start( GTK_BOX(h), b, FALSE, FALSE, 0 );
540
g_signal_connect( w, "toggled", G_CALLBACK(target_cb), b );
542
hig_workarea_add_wide_control( t, &row, h );
544
s = _("_Ignore unencrypted peers");
545
w = gtk_check_button_new_with_mnemonic( s );
546
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w),
547
pref_int_get(PREF_KEY_ENCRYPTION)==TR_ENCRYPTION_REQUIRED );
548
g_signal_connect( w, "toggled", G_CALLBACK(onEncryptionToggled), core );
549
hig_workarea_add_wide_control( t, &row, w );
551
s = _("Use peer e_xchange");
552
w = new_check_button( s, PREF_KEY_PEX, core );
553
hig_workarea_add_wide_control( t, &row, w );
555
h = gtk_hbox_new( FALSE, GUI_PAD_BIG );
556
w2 = new_spin_button( PREF_KEY_PORT, core, 1, INT_MAX, 1 );
557
gtk_box_pack_start( GTK_BOX(h), w2, FALSE, FALSE, 0 );
558
l = gtk_label_new( NULL );
559
gtk_misc_set_alignment( GTK_MISC(l), 0.0f, 0.5f );
560
gtk_box_pack_start( GTK_BOX(h), l, FALSE, FALSE, 0 );
561
hig_workarea_add_row( t, &row, _("Listening _port:"), h, w2 );
563
g_object_set_data( G_OBJECT(l), "tr-port-spin", w2 );
564
g_object_set_data( G_OBJECT(l), "alive", alive );
565
g_object_set_data( G_OBJECT(l), "handle", tr_core_handle( TR_CORE( core ) ) );
566
testing_port_cb( NULL, l );
567
g_signal_connect( w2, "value-changed", G_CALLBACK(testing_port_cb), l );
531
hig_workarea_add_section_title( t, &row, _( "Blocklist" ) );
533
w = new_check_button( "", PREF_KEY_BLOCKLIST_ENABLED, core );
534
updateBlocklistText( w, TR_CORE( core ) );
535
h = gtk_hbox_new( FALSE, GUI_PAD_BIG );
536
gtk_box_pack_start( GTK_BOX( h ), w, TRUE, TRUE, 0 );
537
b = gtr_button_new_from_stock( GTK_STOCK_REFRESH, _( "_Update" ) );
539
g_object_set_data( G_OBJECT( b ), "session",
540
tr_core_session( TR_CORE( core ) ) );
541
g_signal_connect( b, "clicked", G_CALLBACK( onUpdateBlocklistCB ), data );
542
gtk_box_pack_start( GTK_BOX( h ), b, FALSE, FALSE, 0 );
543
g_signal_connect( w, "toggled", G_CALLBACK( target_cb ), b );
545
hig_workarea_add_wide_control( t, &row, h );
547
s = _( "Enable _automatic updates" );
548
w = new_check_button( s, PREF_KEY_BLOCKLIST_UPDATES_ENABLED, core );
549
hig_workarea_add_wide_control( t, &row, w );
550
g_signal_connect( data->check, "toggled", G_CALLBACK( target_cb ), w );
551
target_cb( data->check, w );
569
553
hig_workarea_add_section_divider( t, &row );
570
554
hig_workarea_add_section_title( t, &row, _( "Limits" ) );
572
w = new_spin_button( PREF_KEY_MAX_PEERS_GLOBAL, core, 1, 3000, 5 );
573
hig_workarea_add_row( t, &row, _( "Maximum peers _overall:" ), w, NULL );
574
w = new_spin_button( PREF_KEY_MAX_PEERS_PER_TORRENT, core, 1, 300, 5 );
575
hig_workarea_add_row( t, &row, _( "Maximum peers per _torrent:" ), w, NULL );
556
w = new_spin_button( PREF_KEY_MAX_PEERS_GLOBAL, core, 1, 3000, 5 );
557
hig_workarea_add_row( t, &row, _( "Maximum peers _overall:" ), w, NULL );
558
w = new_spin_button( PREF_KEY_MAX_PEERS_PER_TORRENT, core, 1, 300, 5 );
559
hig_workarea_add_row( t, &row, _(
560
"Maximum peers per _torrent:" ), w, NULL );
562
hig_workarea_add_section_divider( t, &row );
563
hig_workarea_add_section_title ( t, &row, _( "Options" ) );
565
s = _( "_Ignore unencrypted peers" );
566
w = gtk_check_button_new_with_mnemonic( s );
567
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ),
569
PREF_KEY_ENCRYPTION ) ==
570
TR_ENCRYPTION_REQUIRED );
571
g_signal_connect( w, "toggled", G_CALLBACK( onEncryptionToggled ), core );
572
hig_workarea_add_wide_control( t, &row, w );
574
s = _( "Use peer e_xchange" );
575
w = new_check_button( s, PREF_KEY_PEX, core );
576
hig_workarea_add_wide_control( t, &row, w );
577
578
hig_workarea_finish( t, &row );
582
allow_deny_model_new( void )
585
GtkListStore * store = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_CHAR );
586
gtk_list_store_append( store, &iter );
587
gtk_list_store_set( store, &iter, 0, _( "Allow" ), 1, '+', -1 );
588
gtk_list_store_append( store, &iter );
589
gtk_list_store_set( store, &iter, 0, _( "Deny" ), 1, '-', -1 );
590
return GTK_TREE_MODEL( store );
600
592
static GtkTreeModel*
601
acl_tree_model_new( const char * acl )
593
whitelist_tree_model_new( const char * whitelist )
605
597
GtkListStore * store = gtk_list_store_new( N_COLS,
608
rules = g_strsplit( acl, ",", 0 );
610
for( i=0; rules && rules[i]; ++i )
601
rules = g_strsplit( whitelist, ",", 0 );
603
for( i = 0; rules && rules[i]; ++i )
612
606
const char * s = rules[i];
613
607
while( isspace( *s ) ) ++s;
614
if( *s=='+' || *s=='-' )
617
gtk_list_store_append( store, &iter );
618
gtk_list_store_set( store, &iter,
619
COL_PERMISSION, *s=='+' ? _( "Allow" ) : _( "Deny" ) ,
608
gtk_list_store_append( store, &iter );
609
gtk_list_store_set( store, &iter, COL_ADDRESS, s, -1 );
625
612
g_strfreev( rules );
798
783
hig_workarea_add_section_title( t, &row, _( "Web Interface" ) );
800
/* "enabled" checkbutton */
801
s = _( "_Enable web interface" );
802
w = new_check_button( s, PREF_KEY_RPC_ENABLED, core );
803
page->rpc_tb = GTK_TOGGLE_BUTTON( w );
804
g_signal_connect( w, "clicked", G_CALLBACK(onRPCToggled), page );
805
h = gtk_hbox_new( FALSE, GUI_PAD_BIG );
806
gtk_box_pack_start_defaults( GTK_BOX(h), w );
807
w = gtk_button_new_from_stock( GTK_STOCK_OPEN );
808
page->widgets = g_slist_append( page->widgets, w );
809
g_signal_connect( w, "clicked", G_CALLBACK(onLaunchClutchCB), NULL );
810
gtk_box_pack_start( GTK_BOX(h), w, FALSE, FALSE, 0 );
811
hig_workarea_add_wide_control( t, &row, h );
813
/* require authentication */
814
s = _( "_Require username" );
815
w = new_check_button( s, PREF_KEY_RPC_AUTH_ENABLED, core );
816
hig_workarea_add_wide_control( t, &row, w );
817
page->auth_tb = GTK_TOGGLE_BUTTON( w );
818
page->widgets = g_slist_append( page->widgets, w );
819
g_signal_connect( w, "clicked", G_CALLBACK(onRPCToggled), page );
822
s = _( "_Username:" );
823
w = new_entry( PREF_KEY_RPC_USERNAME, core );
824
page->auth_widgets = g_slist_append( page->auth_widgets, w );
825
w = hig_workarea_add_row( t, &row, s, w, NULL );
826
page->auth_widgets = g_slist_append( page->auth_widgets, w );
829
s = _( "Pass_word:" );
830
w = new_entry( PREF_KEY_RPC_PASSWORD, core );
831
gtk_entry_set_visibility( GTK_ENTRY( w ), FALSE );
832
page->auth_widgets = g_slist_append( page->auth_widgets, w );
833
w = hig_workarea_add_row( t, &row, s, w, NULL );
834
page->auth_widgets = g_slist_append( page->auth_widgets, w );
837
w = new_spin_button( PREF_KEY_RPC_PORT, core, 0, 65535, 1 );
838
page->widgets = g_slist_append( page->widgets, w );
839
w = hig_workarea_add_row( t, &row, _( "Listening _port:" ), w, NULL );
840
page->widgets = g_slist_append( page->widgets, w );
842
/* access control list */
844
const char * val = pref_string_get( PREF_KEY_RPC_ACL );
845
GtkTreeModel * m = acl_tree_model_new( val );
785
/* "enabled" checkbutton */
786
s = _( "_Enable web interface" );
787
w = new_check_button( s, PREF_KEY_RPC_ENABLED, core );
788
page->rpc_tb = GTK_TOGGLE_BUTTON( w );
789
g_signal_connect( w, "clicked", G_CALLBACK( onRPCToggled ), page );
790
h = gtk_hbox_new( FALSE, GUI_PAD_BIG );
791
gtk_box_pack_start( GTK_BOX( h ), w, TRUE, TRUE, 0 );
792
w = gtk_button_new_from_stock( GTK_STOCK_OPEN );
793
page->widgets = g_slist_append( page->widgets, w );
794
g_signal_connect( w, "clicked", G_CALLBACK( onLaunchClutchCB ), NULL );
795
gtk_box_pack_start( GTK_BOX( h ), w, FALSE, FALSE, 0 );
796
hig_workarea_add_wide_control( t, &row, h );
799
w = new_spin_button( PREF_KEY_RPC_PORT, core, 0, 65535, 1 );
800
page->widgets = g_slist_append( page->widgets, w );
801
w = hig_workarea_add_row( t, &row, _( "Listening _port:" ), w, NULL );
802
page->widgets = g_slist_append( page->widgets, w );
804
/* require authentication */
805
s = _( "_Require username" );
806
w = new_check_button( s, PREF_KEY_RPC_AUTH_ENABLED, core );
807
hig_workarea_add_wide_control( t, &row, w );
808
page->auth_tb = GTK_TOGGLE_BUTTON( w );
809
page->widgets = g_slist_append( page->widgets, w );
810
g_signal_connect( w, "clicked", G_CALLBACK( onRPCToggled ), page );
813
s = _( "_Username:" );
814
w = new_entry( PREF_KEY_RPC_USERNAME, core );
815
page->auth_widgets = g_slist_append( page->auth_widgets, w );
816
w = hig_workarea_add_row( t, &row, s, w, NULL );
817
page->auth_widgets = g_slist_append( page->auth_widgets, w );
820
s = _( "Pass_word:" );
821
w = new_entry( PREF_KEY_RPC_PASSWORD, core );
822
gtk_entry_set_visibility( GTK_ENTRY( w ), FALSE );
823
page->auth_widgets = g_slist_append( page->auth_widgets, w );
824
w = hig_workarea_add_row( t, &row, s, w, NULL );
825
page->auth_widgets = g_slist_append( page->auth_widgets, w );
827
/* require authentication */
828
s = _( "Only allow the following IP _addresses to connect:" );
829
w = new_check_button( s, PREF_KEY_RPC_WHITELIST_ENABLED, core );
830
hig_workarea_add_wide_control( t, &row, w );
831
page->whitelist_tb = GTK_TOGGLE_BUTTON( w );
832
page->widgets = g_slist_append( page->widgets, w );
833
g_signal_connect( w, "clicked", G_CALLBACK( onRPCToggled ), page );
835
/* access control list */
837
const char * val = pref_string_get( PREF_KEY_RPC_WHITELIST );
838
GtkTreeModel * m = whitelist_tree_model_new( val );
846
839
GtkTreeViewColumn * c;
848
GtkTreeSelection * sel;
852
GtkTooltips * tips = gtk_tooltips_new( );
841
GtkTreeSelection * sel;
854
s = _( "Access control list:" );
855
846
page->store = GTK_LIST_STORE( m );
856
847
w = gtk_tree_view_new_with_model( m );
848
g_signal_connect( w, "button-release-event",
849
G_CALLBACK( on_tree_view_button_released ), NULL );
858
page->widgets = g_slist_append( page->widgets, w );
851
page->whitelist_widgets = g_slist_append( page->whitelist_widgets, w );
859
852
v = page->view = GTK_TREE_VIEW( w );
860
gtk_tooltips_set_tip( tips, w,
861
_( "IP addresses may use wildcards, such as 192.168.*.*" ),
853
#if GTK_CHECK_VERSION( 2,12,0 )
854
gtk_widget_set_tooltip_text( w,
855
_( "IP addresses may use wildcards, such as 192.168.*.*" ) );
863
857
sel = gtk_tree_view_get_selection( v );
864
858
g_signal_connect( sel, "changed",
865
G_CALLBACK( onACLSelectionChanged ), page );
859
G_CALLBACK( onWhitelistSelectionChanged ), page );
866
860
g_object_unref( G_OBJECT( m ) );
867
861
gtk_tree_view_set_headers_visible( v, TRUE );
868
862
w = gtk_frame_new( NULL );
975
onProxyTypeChanged( GtkComboBox * w, gpointer gpage )
968
onProxyTypeChanged( GtkComboBox * w,
977
971
GtkTreeIter iter;
978
973
if( gtk_combo_box_get_active_iter( w, &iter ) )
980
975
struct ProxyPage * page = gpage;
981
int type = TR_PROXY_HTTP;
982
gtk_tree_model_get( gtk_combo_box_get_model( w ), &iter, 1, &type, -1 );
983
tr_core_set_pref_int( TR_CORE( page->core ), PREF_KEY_PROXY_TYPE, type );
976
int type = TR_PROXY_HTTP;
977
gtk_tree_model_get( gtk_combo_box_get_model(
978
w ), &iter, 1, &type, -1 );
979
tr_core_set_pref_int( TR_CORE(
980
page->core ), PREF_KEY_PROXY_TYPE, type );
987
984
static GtkWidget*
988
985
trackerPage( GObject * core )
996
993
struct ProxyPage * page = tr_new0( struct ProxyPage, 1 );
998
995
page->core = TR_CORE( core );
1000
997
t = hig_workarea_create( );
1001
hig_workarea_add_section_title (t, &row, _( "Tracker Proxy" ) );
1003
s = _( "Connect to tracker via a pro_xy" );
1004
w = new_check_button( s, PREF_KEY_PROXY_SERVER_ENABLED, core );
1005
g_signal_connect( w, "toggled", G_CALLBACK(onProxyToggled), page );
1006
hig_workarea_add_wide_control( t, &row, w );
1008
s = _( "Proxy _server:" );
1009
w = new_entry( PREF_KEY_PROXY_SERVER, core );
1010
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1011
w = hig_workarea_add_row( t, &row, s, w, NULL );
1012
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1014
w = new_spin_button( PREF_KEY_PROXY_PORT, core, 0, 65536, 1 );
1015
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1016
w = hig_workarea_add_row( t, &row, _( "Proxy _port:" ), w, NULL );
1017
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1019
s = _( "Proxy _type:" );
1020
m = proxyTypeModelNew( );
1021
w = gtk_combo_box_new_with_model( m );
1022
r = gtk_cell_renderer_text_new( );
1023
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( w ), r, TRUE );
1024
gtk_cell_layout_set_attributes( GTK_CELL_LAYOUT( w ), r, "text", 0, NULL );
1025
gtk_combo_box_set_active( GTK_COMBO_BOX( w ), pref_int_get( PREF_KEY_PROXY_TYPE ) );
1026
g_signal_connect( w, "changed", G_CALLBACK(onProxyTypeChanged), page );
1027
g_object_unref( G_OBJECT( m ) );
1028
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1029
w = hig_workarea_add_row( t, &row, s, w, NULL );
1030
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1032
s = _( "_Authentication is required" );
1033
w = new_check_button( s, PREF_KEY_PROXY_AUTH_ENABLED, core );
1034
g_signal_connect( w, "toggled", G_CALLBACK(onProxyToggled), page );
1035
hig_workarea_add_wide_control( t, &row, w );
1036
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1038
s = _( "_Username:" );
1039
w = new_entry( PREF_KEY_PROXY_USERNAME, core );
1040
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
1041
w = hig_workarea_add_row( t, &row, s, w, NULL );
1042
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
1044
s = _( "Pass_word:" );
1045
w = new_entry( PREF_KEY_PROXY_PASSWORD, core );
1046
gtk_entry_set_visibility( GTK_ENTRY( w ), FALSE );
1047
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
1048
w = hig_workarea_add_row( t, &row, s, w, NULL );
1049
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
998
hig_workarea_add_section_title ( t, &row, _( "Tracker Proxy" ) );
1000
s = _( "Connect to tracker via a pro_xy" );
1001
w = new_check_button( s, PREF_KEY_PROXY_SERVER_ENABLED, core );
1002
g_signal_connect( w, "toggled", G_CALLBACK( onProxyToggled ), page );
1003
hig_workarea_add_wide_control( t, &row, w );
1005
s = _( "Proxy _server:" );
1006
w = new_entry( PREF_KEY_PROXY_SERVER, core );
1007
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1008
w = hig_workarea_add_row( t, &row, s, w, NULL );
1009
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1011
w = new_spin_button( PREF_KEY_PROXY_PORT, core, 0, 65535, 1 );
1012
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1013
w = hig_workarea_add_row( t, &row, _( "Proxy _port:" ), w, NULL );
1014
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1016
s = _( "Proxy _type:" );
1017
m = proxyTypeModelNew( );
1018
w = gtk_combo_box_new_with_model( m );
1019
r = gtk_cell_renderer_text_new( );
1020
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( w ), r, TRUE );
1021
gtk_cell_layout_set_attributes( GTK_CELL_LAYOUT(
1022
w ), r, "text", 0, NULL );
1023
gtk_combo_box_set_active( GTK_COMBO_BOX( w ),
1024
pref_int_get( PREF_KEY_PROXY_TYPE ) );
1025
g_signal_connect( w, "changed", G_CALLBACK( onProxyTypeChanged ), page );
1026
g_object_unref( G_OBJECT( m ) );
1027
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1028
w = hig_workarea_add_row( t, &row, s, w, NULL );
1029
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1031
s = _( "_Authentication is required" );
1032
w = new_check_button( s, PREF_KEY_PROXY_AUTH_ENABLED, core );
1033
g_signal_connect( w, "toggled", G_CALLBACK( onProxyToggled ), page );
1034
hig_workarea_add_wide_control( t, &row, w );
1035
page->proxy_widgets = g_slist_append( page->proxy_widgets, w );
1037
s = _( "_Username:" );
1038
w = new_entry( PREF_KEY_PROXY_USERNAME, core );
1039
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
1040
w = hig_workarea_add_row( t, &row, s, w, NULL );
1041
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
1043
s = _( "Pass_word:" );
1044
w = new_entry( PREF_KEY_PROXY_PASSWORD, core );
1045
gtk_entry_set_visibility( GTK_ENTRY( w ), FALSE );
1046
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
1047
w = hig_workarea_add_row( t, &row, s, w, NULL );
1048
page->proxy_auth_widgets = g_slist_append( page->proxy_auth_widgets, w );
1051
1050
hig_workarea_finish( t, &row );
1052
1051
g_object_set_data_full( G_OBJECT( t ), "page", page, proxyPageFree );
1061
struct BandwidthPage
1064
GSList * sched_widgets;
1068
refreshSchedSensitivity( struct BandwidthPage * p )
1071
const gboolean sched_enabled = pref_flag_get(
1072
PREF_KEY_SCHED_LIMIT_ENABLED );
1074
for( l = p->sched_widgets; l != NULL; l = l->next )
1075
gtk_widget_set_sensitive( GTK_WIDGET( l->data ), sched_enabled );
1079
onSchedToggled( GtkToggleButton * tb UNUSED,
1080
gpointer user_data )
1082
refreshSchedSensitivity( user_data );
1086
onTimeComboChanged( GtkComboBox * w,
1091
if( gtk_combo_box_get_active_iter( w, &iter ) )
1093
const char * key = g_object_get_data( G_OBJECT( w ), PREF_KEY );
1095
gtk_tree_model_get( gtk_combo_box_get_model(
1096
w ), &iter, 0, &val, -1 );
1097
tr_core_set_pref_int( TR_CORE( core ), key, val );
1102
new_time_combo( GObject * core,
1108
GtkCellRenderer * r;
1109
GtkListStore * store;
1111
/* build a store at 15 minute intervals */
1112
store = gtk_list_store_new( 2, G_TYPE_INT, G_TYPE_STRING );
1113
for( i = 0; i < 60 * 24; i += 15 )
1118
tm.tm_hour = i / 60;
1120
strftime( buf, sizeof( buf ), "%I:%M %p", &tm );
1121
gtk_list_store_append( store, &iter );
1122
gtk_list_store_set( store, &iter, 0, i, 1, buf, -1 );
1125
/* build the widget */
1126
w = gtk_combo_box_new_with_model( GTK_TREE_MODEL( store ) );
1127
gtk_combo_box_set_wrap_width( GTK_COMBO_BOX( w ), 4 );
1128
r = gtk_cell_renderer_text_new( );
1129
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( w ), r, TRUE );
1130
gtk_cell_layout_set_attributes( GTK_CELL_LAYOUT(
1131
w ), r, "text", 1, NULL );
1132
g_object_set_data_full( G_OBJECT( w ), PREF_KEY, tr_strdup(
1134
val = pref_int_get( key );
1135
gtk_combo_box_set_active( GTK_COMBO_BOX( w ), val / ( 15 ) );
1136
g_signal_connect( w, "changed", G_CALLBACK( onTimeComboChanged ), core );
1139
g_object_unref( G_OBJECT( store ) );
1144
bandwidthPageFree( gpointer gpage )
1146
struct BandwidthPage * page = gpage;
1148
g_slist_free( page->sched_widgets );
1153
bandwidthPage( GObject * core )
1158
GtkWidget * w, * w2, * h, * l;
1159
struct BandwidthPage * page = tr_new0( struct BandwidthPage, 1 );
1161
page->core = TR_CORE( core );
1163
t = hig_workarea_create( );
1164
hig_workarea_add_section_title( t, &row, _( "Limits" ) );
1166
s = _( "Limit _download speed (KB/s):" );
1167
w = new_check_button( s, PREF_KEY_DL_LIMIT_ENABLED, core );
1168
w2 = new_spin_button( PREF_KEY_DL_LIMIT, core, 0, INT_MAX, 5 );
1169
gtk_widget_set_sensitive( GTK_WIDGET( w2 ),
1170
pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED ) );
1171
g_signal_connect( w, "toggled", G_CALLBACK( target_cb ), w2 );
1172
hig_workarea_add_row_w( t, &row, w, w2, NULL );
1174
s = _( "Limit _upload speed (KB/s):" );
1175
w = new_check_button( s, PREF_KEY_UL_LIMIT_ENABLED, core );
1176
w2 = new_spin_button( PREF_KEY_UL_LIMIT, core, 0, INT_MAX, 5 );
1177
gtk_widget_set_sensitive( GTK_WIDGET( w2 ),
1178
pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED ) );
1179
g_signal_connect( w, "toggled", G_CALLBACK( target_cb ), w2 );
1180
hig_workarea_add_row_w( t, &row, w, w2, NULL );
1182
hig_workarea_add_section_divider( t, &row );
1183
hig_workarea_add_section_title( t, &row, _( "Scheduled Limits" ) );
1185
h = gtk_hbox_new( FALSE, 0 );
1186
w2 = new_time_combo( core, PREF_KEY_SCHED_BEGIN );
1187
page->sched_widgets = g_slist_append( page->sched_widgets, w2 );
1188
gtk_box_pack_start( GTK_BOX( h ), w2, FALSE, FALSE, 0 );
1189
w2 = gtk_label_new ( _( " and " ) );
1190
page->sched_widgets = g_slist_append( page->sched_widgets, w2 );
1191
gtk_box_pack_start( GTK_BOX( h ), w2, FALSE, FALSE, 0 );
1192
w2 = new_time_combo( core, PREF_KEY_SCHED_END );
1193
page->sched_widgets = g_slist_append( page->sched_widgets, w2 );
1194
gtk_box_pack_start( GTK_BOX( h ), w2, FALSE, FALSE, 0 );
1196
s = _( "_Limit bandwidth between" );
1197
w = new_check_button( s, PREF_KEY_SCHED_LIMIT_ENABLED, core );
1198
g_signal_connect( w, "toggled", G_CALLBACK( onSchedToggled ), page );
1199
hig_workarea_add_row_w( t, &row, w, h, NULL );
1201
w = new_spin_button( PREF_KEY_SCHED_DL_LIMIT, core, 0, INT_MAX, 5 );
1202
page->sched_widgets = g_slist_append( page->sched_widgets, w );
1203
l = hig_workarea_add_row( t, &row, _(
1204
"Limit d_ownload speed (KB/s):" ), w,
1206
page->sched_widgets = g_slist_append( page->sched_widgets, l );
1208
w = new_spin_button( PREF_KEY_SCHED_UL_LIMIT, core, 0, INT_MAX, 5 );
1209
page->sched_widgets = g_slist_append( page->sched_widgets, w );
1210
l = hig_workarea_add_row( t, &row, _(
1211
"Limit u_pload speed (KB/s):" ), w, NULL );
1212
page->sched_widgets = g_slist_append( page->sched_widgets, l );
1214
hig_workarea_finish( t, &row );
1215
g_object_set_data_full( G_OBJECT( t ), "page", page, bandwidthPageFree );
1217
refreshSchedSensitivity( page );
1225
struct test_port_data
1232
/* this is invoked in the gtk main loop's thread */
1234
testing_port_done_idle( gpointer gdata )
1236
struct test_port_data * data = gdata;
1240
gdk_threads_enter( );
1241
gtk_label_set_markup( GTK_LABEL( data->label ), data->text );
1242
gdk_threads_leave( );
1248
/* this is invoked in the libtransmission thread */
1250
testing_port_done( tr_session * session UNUSED,
1251
long response_code UNUSED,
1252
const void * response,
1253
size_t response_len,
1256
struct test_port_data * data = gdata;
1260
const int isOpen = response_len && *(char*)response == '1';
1261
g_snprintf( data->text, sizeof( data->text ), isOpen
1262
? _( "Port is <b>open</b>" )
1263
: _( "Port is <b>closed</b>" ) );
1264
g_idle_add( testing_port_done_idle, data );
1269
testing_port_begin( gpointer gdata )
1271
struct test_port_data * data = gdata;
1276
GObject * o = G_OBJECT( data->label );
1277
GtkSpinButton * spin = g_object_get_data( o, "tr-port-spin" );
1278
tr_session * session = g_object_get_data( o, "session" );
1279
const int port = gtk_spin_button_get_value_as_int( spin );
1280
g_snprintf( url, sizeof( url ),
1281
"http://portcheck.transmissionbt.com/%d",
1283
tr_webRun( session, url, NULL, testing_port_done, data );
1288
struct network_page_data
1297
onCorePrefsChanged( TrCore * core UNUSED,
1301
if( !strcmp( key, PREF_KEY_PORT ) )
1303
struct network_page_data * ndata = gdata;
1304
struct test_port_data * data;
1306
gtk_label_set_markup( GTK_LABEL( ndata->label ),
1307
_( "<i>Testing port...</i>" ) );
1309
/* wait three seconds to give the port forwarding time to kick in */
1310
data = g_new0( struct test_port_data, 1 );
1311
data->label = ndata->label;
1312
data->alive = ndata->alive;
1313
g_timeout_add( 3000, testing_port_begin, data );
1318
networkPageDestroyed( gpointer gdata,
1319
GObject * dead UNUSED )
1321
struct network_page_data * data = gdata;
1323
*data->alive = FALSE;
1324
g_signal_handler_disconnect( data->core, data->id );
1058
1328
static GtkWidget*
1059
1329
networkPage( GObject * core )
1064
GtkWidget * w, * w2;
1338
struct network_page_data * data;
1340
/* register to stop listening to core prefs changes when the page is
1342
data = g_new0( struct network_page_data, 1 );
1343
data->core = TR_CORE( core );
1345
/* we leak this gboolean* s.t. we know it will still be alive when the port
1346
check is done, whether the dialog was destroyed or not. kind of
1348
data->alive = g_new( gboolean, 1 );
1349
*data->alive = TRUE;
1351
/* build the page */
1066
1352
t = hig_workarea_create( );
1067
hig_workarea_add_section_title (t, &row, _( "Router" ) );
1069
s = _("Use UPnP or NAT-PMP port _forwarding from my router" );
1070
w = new_check_button( s, PREF_KEY_PORT_FORWARDING, core );
1071
hig_workarea_add_wide_control( t, &row, w );
1073
hig_workarea_add_section_divider( t, &row );
1074
hig_workarea_add_section_title (t, &row, _("Bandwidth"));
1076
s = _("Limit _download speed (KB/s):");
1077
w = new_check_button( s, PREF_KEY_DL_LIMIT_ENABLED, core );
1078
w2 = new_spin_button( PREF_KEY_DL_LIMIT, core, 0, INT_MAX, 5 );
1079
gtk_widget_set_sensitive( GTK_WIDGET(w2), pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED ) );
1080
g_signal_connect( w, "toggled", G_CALLBACK(target_cb), w2 );
1081
hig_workarea_add_row_w( t, &row, w, w2, NULL );
1083
s = _("Limit _upload speed (KB/s):");
1084
w = new_check_button( s, PREF_KEY_UL_LIMIT_ENABLED, core );
1085
w2 = new_spin_button( PREF_KEY_UL_LIMIT, core, 0, INT_MAX, 5 );
1086
gtk_widget_set_sensitive( GTK_WIDGET(w2), pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED ) );
1087
g_signal_connect( w, "toggled", G_CALLBACK(target_cb), w2 );
1088
hig_workarea_add_row_w( t, &row, w, w2, NULL );
1353
hig_workarea_add_section_title( t, &row, _( "Incoming Peers" ) );
1355
h = gtk_hbox_new( FALSE, GUI_PAD_BIG );
1356
w2 = new_spin_button( PREF_KEY_PORT, core, 1, 65535, 1 );
1357
gtk_box_pack_start( GTK_BOX( h ), w2, FALSE, FALSE, 0 );
1358
data->label = l = gtk_label_new( NULL );
1359
gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
1360
gtk_box_pack_start( GTK_BOX( h ), l, FALSE, FALSE, 0 );
1361
hig_workarea_add_row( t, &row, _( "Listening _port:" ), h, w2 );
1363
g_object_set_data( G_OBJECT( l ), "tr-port-spin", w2 );
1364
g_object_set_data( G_OBJECT( l ), "session",
1365
tr_core_session( TR_CORE( core ) ) );
1366
data->id = g_signal_connect( TR_CORE(
1367
core ), "prefs-changed",
1368
G_CALLBACK( onCorePrefsChanged ), data );
1369
onCorePrefsChanged( NULL, PREF_KEY_PORT, data );
1371
s = _( "Use UPnP or NAT-PMP port _forwarding from my router" );
1372
w = new_check_button( s, PREF_KEY_PORT_FORWARDING, core );
1373
hig_workarea_add_wide_control( t, &row, w );
1090
1375
hig_workarea_finish( t, &row );
1376
g_object_weak_ref( G_OBJECT( t ), networkPageDestroyed, data );
1095
tr_prefs_dialog_new( GObject * core, GtkWindow * parent )
1386
tr_prefs_dialog_new( GObject * core,
1387
GtkWindow * parent )
1101
alive = g_new( gboolean, 1 );
1104
d = gtk_dialog_new_with_buttons( _( "Transmission Preferences" ), parent,
1392
d = gtk_dialog_new_with_buttons( _(
1393
"Transmission Preferences" ),
1105
1395
GTK_DIALOG_DESTROY_WITH_PARENT,
1106
1396
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
1107
1397
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
1109
gtk_window_set_role( GTK_WINDOW(d), "transmission-preferences-dialog" );
1399
gtk_window_set_role( GTK_WINDOW( d ), "transmission-preferences-dialog" );
1110
1400
gtk_dialog_set_has_separator( GTK_DIALOG( d ), FALSE );
1111
1401
gtk_container_set_border_width( GTK_CONTAINER( d ), GUI_PAD );
1112
g_object_weak_ref( G_OBJECT( d ), dialogDestroyed, alive );
1114
1403
n = gtk_notebook_new( );
1115
1404
gtk_container_set_border_width ( GTK_CONTAINER ( n ), GUI_PAD );
1117
1406
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1118
1407
torrentPage( core ),
1119
gtk_label_new (_("Torrents")) );
1120
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1121
peerPage( core, alive ),
1122
gtk_label_new (_("Peers")) );
1123
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1124
trackerPage( core ),
1125
gtk_label_new (_("Trackers")) );
1408
gtk_label_new ( _( "Torrents" ) ) );
1409
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1411
gtk_label_new ( _( "Peers" ) ) );
1126
1412
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1127
1413
networkPage( core ),
1128
gtk_label_new (_("Network")) );
1414
gtk_label_new ( _( "Network" ) ) );
1415
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1416
desktopPage( core ),
1417
gtk_label_new ( _( "Desktop" ) ) );
1418
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1419
bandwidthPage( core ),
1420
gtk_label_new ( _( "Bandwidth" ) ) );
1129
1421
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1130
1422
webPage( core ),
1131
gtk_label_new (_("Web")) );
1423
gtk_label_new ( _( "Web" ) ) );
1424
gtk_notebook_append_page( GTK_NOTEBOOK( n ),
1425
trackerPage( core ),
1426
gtk_label_new ( _( "Trackers" ) ) );
1133
g_signal_connect( d, "response", G_CALLBACK(response_cb), core );
1134
gtk_box_pack_start_defaults( GTK_BOX(GTK_DIALOG(d)->vbox), n );
1135
gtk_widget_show_all( GTK_DIALOG(d)->vbox );
1428
g_signal_connect( d, "response", G_CALLBACK( response_cb ), core );
1429
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( d )->vbox ), n, TRUE, TRUE, 0 );
1430
gtk_widget_show_all( GTK_DIALOG( d )->vbox );