From 713ded5ff47ba7bcda5be34a10b4dce22b135d37 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 27 Sep 2007 20:57:58 +0000 Subject: [PATCH] preferences code refresh in the gtk+ client --- gtk/conf.c | 231 +++++----- gtk/conf.h | 37 +- gtk/dialogs.c | 28 +- gtk/ipc.c | 51 +- gtk/main.c | 143 +++--- gtk/msgwin.c | 9 +- gtk/tr_core.c | 102 ++-- gtk/tr_core.h | 6 +- gtk/tr_prefs.c | 1153 ++++++++-------------------------------------- gtk/tr_prefs.h | 132 ++---- gtk/tr_torrent.c | 4 +- gtk/util.c | 35 +- gtk/util.h | 7 +- 13 files changed, 534 insertions(+), 1404 deletions(-) diff --git a/gtk/conf.c b/gtk/conf.c index d97a91bf7..7ace5c320 100644 --- a/gtk/conf.c +++ b/gtk/conf.c @@ -36,6 +36,9 @@ #include #include +#include +#include + #include "conf.h" #include "util.h" @@ -65,14 +68,11 @@ cf_benc_append(benc_val_t *val, char type, int incsize); static void cf_writebenc(const char *file, const char *tmp, benc_val_t *data, char **errstr); -static gboolean -writefile_traverse(gpointer key, gpointer value, gpointer data); static char * getstateval(benc_val_t *state, char *line); static char *gl_confdir = NULL; static char *gl_old_confdir = NULL; -static GTree *gl_prefs = NULL; static char *gl_lockpath = NULL; static char *gl_old_lockpath = NULL; @@ -180,7 +180,7 @@ cf_readfile(const char *file, const char *oldfile, gsize *len, gboolean *usedold, char **errstr) { char *path; GIOChannel *io; - GError *err; + GError *err = NULL; char *ret; *errstr = NULL; @@ -222,69 +222,112 @@ cf_readfile(const char *file, const char *oldfile, gsize *len, return ret; } -void -cf_loadprefs(char **errstr) { - char *data, *line, *eol, *sep, *key; - gsize len; - benc_val_t val; - gboolean usedold; - int ii; +/** +*** Prefs Files +**/ - *errstr = NULL; +#define DEFAULT_GROUP "general" - if(NULL != gl_prefs) - g_tree_destroy(gl_prefs); - - gl_prefs = g_tree_new_full((GCompareDataFunc)g_ascii_strcasecmp, NULL, - g_free, g_free); - - data = cf_readfile(FILE_PREFS, OLD_FILE_PREFS, &len, &usedold, errstr); - if(NULL != *errstr) { - g_assert(NULL == data); - return; - } - - if(NULL == data) - return; - - memset(&val, 0, sizeof(val)); - if(!usedold && !tr_bencLoad(data, len, &val, NULL)) { - if(TYPE_DICT == val.type) { - key = NULL; - for(ii = 0; ii < val.val.l.count; ii++) { - if(NULL == key) { - g_assert(TYPE_STR == val.val.l.vals[ii].type); - key = val.val.l.vals[ii].val.s.s; - } else { - if(TYPE_INT == val.val.l.vals[ii].type) - g_tree_insert(gl_prefs, g_strdup(key), - g_strdup_printf("%"PRIu64, val.val.l.vals[ii].val.i)); - else if(TYPE_STR == val.val.l.vals[ii].type) - g_tree_insert(gl_prefs, g_strdup(key), - g_strdup(val.val.l.vals[ii].val.s.s)); - key = NULL; - } - } - } - - } else { - /* XXX remove this in a release or two */ - for(line = data; NULL != (eol = strchr(line, PREF_SEP_LINE)); - line = eol + 1) { - *eol = '\0'; - if(g_utf8_validate(line, -1, NULL) && - NULL != (sep = strchr(line, PREF_SEP_KEYVAL))) { - *sep = '\0'; - g_tree_insert(gl_prefs, g_strcompress(line), g_strcompress(sep+1)); - } - } - cf_saveprefs(errstr); - } - - tr_bencFree(&val); - g_free(data); +static char* +getPrefsFilename( void ) +{ + return g_build_filename( tr_getPrefsDirectory(), "gtk", "prefs", NULL ); } +static GKeyFile* +getPrefsKeyFile( void ) +{ + static GKeyFile * myKeyFile = NULL; + + if( myKeyFile == NULL ) + { + char * filename = getPrefsFilename( ); + myKeyFile = g_key_file_new( ); + g_key_file_load_from_file( myKeyFile, filename, 0, NULL ); + g_free( filename ); + } + + return myKeyFile; +} + +int +pref_int_get( const char * key ) +{ + return g_key_file_get_integer( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ); +} +void +pref_int_set( const char * key, int value ) +{ + g_key_file_set_integer( getPrefsKeyFile( ), DEFAULT_GROUP, key, value ); +} +void +pref_int_set_default( const char * key, int value ) +{ + if( !g_key_file_has_key( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ) ) + pref_int_set( key, value ); +} + +gboolean +pref_flag_get ( const char * key ) +{ + return g_key_file_get_boolean( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ); +} +void +pref_flag_set( const char * key, gboolean value ) +{ + g_key_file_set_boolean( getPrefsKeyFile( ), DEFAULT_GROUP, key, value ); +} +void +pref_flag_set_default( const char * key, gboolean value ) +{ + if( !g_key_file_has_key( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ) ) + pref_flag_set( key, value ); +} + +char* +pref_string_get( const char * key ) +{ + return g_key_file_get_string( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ); +} +void +pref_string_set( const char * key, const char * value ) +{ + g_key_file_set_string( getPrefsKeyFile( ), DEFAULT_GROUP, key, value ); +} +void +pref_string_set_default( const char * key, const char * value ) +{ + if( !g_key_file_has_key( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ) ) + pref_string_set( key, value ); +} + +void +pref_save(char **errstr) +{ + GError * err = NULL; + gsize datalen; + char * data; + char * filename = getPrefsFilename( ); + + data = g_key_file_to_data( getPrefsKeyFile(), &datalen, &err ); + if( !err ) { + GIOChannel * out = g_io_channel_new_file( filename, "w+", &err ); + g_io_channel_write_chars( out, data, datalen, NULL, &err ); + g_io_channel_unref( out ); + } + + if( errstr != NULL ) + *errstr = err ? g_strdup( err->message ) : NULL; + + g_free( filename ); + g_free( data ); + g_clear_error( &err ); +} + +/** +*** +**/ + benc_val_t * cf_loadstate(char **errstr) { char *data, *line, *eol, *prog; @@ -337,27 +380,13 @@ cf_benc_append(benc_val_t *val, char type, int incsize) { val->val.l.vals[val->val.l.count-1].type = type; } -const char * -cf_getpref(const char *name) { - g_assert(NULL != gl_prefs); - - return g_tree_lookup(gl_prefs, name); -} - -void -cf_setpref(const char *name, const char *value) { - g_assert(NULL != gl_prefs); - - g_tree_insert(gl_prefs, g_strdup(name), g_strdup(value)); -} - static void cf_writebenc(const char *file, const char *tmp, benc_val_t *data, char **errstr) { char *path = g_build_filename(gl_confdir, file, NULL); char *pathtmp = g_build_filename(gl_confdir, tmp, NULL); GIOChannel *io = NULL; - GError *err; + GError *err = NULL; char *datastr; int len; gsize written; @@ -402,45 +431,25 @@ cf_writebenc(const char *file, const char *tmp, benc_val_t *data, free(datastr); } -void -cf_saveprefs(char **errstr) { - benc_val_t val; - benc_val_t *ptr; - - *errstr = NULL; - - memset(&val, 0, sizeof(val)); - val.type = TYPE_DICT; - val.val.l.alloc = val.val.l.count = g_tree_nnodes(gl_prefs) * 2; - val.val.l.vals = g_new0(benc_val_t, val.val.l.alloc); - - ptr = val.val.l.vals; - g_tree_foreach(gl_prefs, writefile_traverse, &ptr); - g_assert(ptr - val.val.l.vals == val.val.l.alloc); - - cf_writebenc(FILE_PREFS, FILE_PREFS_TMP, &val, errstr); - tr_bencFree(&val); -} - static gboolean -writefile_traverse(gpointer key, gpointer value, gpointer data) { - benc_val_t **ptr = data; - benc_val_t *bkey = *ptr; - benc_val_t *bval = (*ptr) + 1; +strbool( const char * str ) +{ + if( !str ) + return FALSE; - *ptr = (*ptr) + 2; - - bkey->type = TYPE_STR; - bkey->val.s.s = g_strdup(key); - bkey->val.s.i = strlen(key); - - bval->type = TYPE_STR; - bval->val.s.s = g_strdup(value); - bval->val.s.i = strlen(value); + switch(str[0]) { + case 'y': case 't': case 'Y': case '1': case 'j': case 'e': + return TRUE; + default: + if(0 == g_ascii_strcasecmp("on", str)) + return TRUE; + break; + } return FALSE; } + static char * getstateval(benc_val_t *state, char *line) { char *start, *end; diff --git a/gtk/conf.h b/gtk/conf.h index 89b62f226..2f7b79602 100644 --- a/gtk/conf.h +++ b/gtk/conf.h @@ -22,11 +22,32 @@ * DEALINGS IN THE SOFTWARE. *****************************************************************************/ +/** +*** +**/ + #ifndef TG_CONF_H #define TG_CONF_H -#include -#include +int pref_int_get ( const char * key ); +void pref_int_set ( const char * key, int value ); +void pref_int_set_default ( const char * key, int default_value ); + +gboolean pref_flag_get ( const char * key ); +void pref_flag_set ( const char * key, gboolean value ); +void pref_flag_set_default ( const char * key, gboolean default_value ); + +char* pref_string_get ( const char * key ); +void pref_string_set ( const char * key, const char * value ); +void pref_string_set_default ( const char * key, const char * default_value ); + +void pref_save ( char **errstr ); + +/** +*** +**/ + +struct benc_val_s; gboolean cf_init(const char *confdir, char **errstr); @@ -36,17 +57,11 @@ char * cf_sockname(void); void cf_loadprefs(char **errstr); -const char * -cf_getpref(const char *name); -void -cf_setpref(const char *name, const char *value); -void -cf_saveprefs(char **errstr); -benc_val_t * +struct benc_val_s * cf_loadstate(char **errstr); void -cf_savestate(benc_val_t *state, char **errstr); +cf_savestate(struct benc_val_s *state, char **errstr); void -cf_freestate(benc_val_t *state); +cf_freestate(struct benc_val_s *state); #endif /* TG_CONF_H */ diff --git a/gtk/dialogs.c b/gtk/dialogs.c index c8f7f20db..2f1082701 100644 --- a/gtk/dialogs.c +++ b/gtk/dialogs.c @@ -129,7 +129,7 @@ makeaddwind( GtkWindow * parent, TrCore * core ) GtkFileFilter *unfilter = gtk_file_filter_new(); GtkWidget *getdir = gtk_file_chooser_button_new( _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); - const char * pref; + char * pref; data->widget = wind; data->core = core; @@ -148,10 +148,10 @@ makeaddwind( GtkWindow * parent, TrCore * core ) gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE); - pref = tr_prefs_get( PREF_ID_DIR ); - if( NULL != pref ) - { + pref = pref_string_get( PREF_KEY_DIR_DEFAULT ); + if( pref != NULL ) { gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( wind ), pref ); + g_free( pref ); } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE); @@ -214,7 +214,8 @@ addresp(GtkWidget *widget, gint resp, gpointer gdata) { if(data->usingaltdir) dir = gtk_file_chooser_get_filename(data->altdir); files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - action = toraddaction( tr_prefs_get( PREF_ID_ADDSTD ) ); + action = tr_prefs_get_action( PREF_KEY_ADDSTD ); + if( NULL == dir ) { stupidgtk = NULL; @@ -268,6 +269,7 @@ void promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data, size_t size, enum tr_torrent_action act, gboolean paused ) { + char * path; struct dirdata * stuff; GtkWidget * wind; @@ -295,8 +297,9 @@ promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data, NULL ); gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( wind ), TRUE ); gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( wind ), FALSE ); - gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ), - getdownloaddir() ); + path = getdownloaddir( ); + gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ), path ); + g_free( path ); stuff->widget = wind; @@ -372,13 +375,10 @@ struct quitdata static void quitresp( GtkWidget * widget, int response, gpointer data ) { - struct quitdata * stuff; - gboolean doask; + struct quitdata * stuff = data; - stuff = data; - - doask = !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(stuff->dontask) ); - tr_core_set_pref_bool( stuff->core, PREF_ID_ASKQUIT, doask ); + pref_flag_set( PREF_KEY_ASKQUIT, + !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(stuff->dontask) ) ); if( response == GTK_RESPONSE_ACCEPT ) stuff->func( stuff->cbdata ); @@ -397,7 +397,7 @@ askquit( TrCore * core, GtkWidget * wind; GtkWidget * dontask; - if( !tr_prefs_get_bool_with_default( PREF_ID_ASKQUIT ) ) + if( !pref_flag_get( PREF_KEY_ASKQUIT ) ) { func( cbdata ); return; diff --git a/gtk/ipc.c b/gtk/ipc.c index a6d519c68..6cc702f62 100644 --- a/gtk/ipc.c +++ b/gtk/ipc.c @@ -590,7 +590,7 @@ smsg_add( enum ipc_msg id SHUTUP, benc_val_t * val, int64_t tag, void * arg ) return; } - action = toraddaction( tr_prefs_get( PREF_ID_ADDIPC ) ); + action = tr_prefs_get_action( PREF_KEY_ADDIPC ); for( ii = 0; ii < val->val.l.count; ii++ ) { path = val->val.l.vals + ii; @@ -637,7 +637,7 @@ smsg_addone( enum ipc_msg id SHUTUP, benc_val_t * val, int64_t tag, return; } - action = toraddaction( tr_prefs_get( PREF_ID_ADDIPC ) ); + action = tr_prefs_get_action( PREF_KEY_ADDIPC ); paused = ( NULL == start || start->val.i ? FALSE : TRUE ); if( NULL != file ) { @@ -997,33 +997,28 @@ smsg_pref( enum ipc_msg id, benc_val_t * val SHUTUP, int64_t tag, void * arg ) buf = ipc_mkint( con->ipc, &size, IPC_MSG_AUTOSTART, tag, 1 ); break; case IPC_MSG_GETDIR: - pref = tr_prefs_get( PREF_ID_ASKDIR ); /* XXX sending back "" when we're prompting is kind of bogus */ - pref = strbool( pref ) ? "" : getdownloaddir(); + pref = pref_flag_get( PREF_KEY_DIR_ASK ) ? "" : getdownloaddir(); buf = ipc_mkstr( con->ipc, &size, IPC_MSG_DIR, tag, pref ); break; case IPC_MSG_GETDOWNLIMIT: - num = -1; - if( tr_prefs_get_bool_with_default( PREF_ID_USEDOWNLIMIT ) ) - { - num = tr_prefs_get_int_with_default( PREF_ID_DOWNLIMIT ); - } + num = pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED ) + ? pref_int_get( PREF_KEY_DL_LIMIT ) + : -1; buf = ipc_mkint( con->ipc, &size, IPC_MSG_DOWNLIMIT, tag, num ); break; case IPC_MSG_GETPEX: buf = ipc_mkint( con->ipc, &size, IPC_MSG_PEX, tag, - tr_prefs_get_bool_with_default( PREF_ID_PEX ) ); + pref_flag_get( PREF_KEY_PEX ) ); break; case IPC_MSG_GETPORT: buf = ipc_mkint( con->ipc, &size, IPC_MSG_PORT, tag, - tr_prefs_get_int_with_default( PREF_ID_PORT ) ); + pref_flag_get( PREF_KEY_PORT ) ); break; case IPC_MSG_GETUPLIMIT: - num = -1; - if( tr_prefs_get_bool_with_default( PREF_ID_USEUPLIMIT ) ) - { - num = tr_prefs_get_int_with_default( PREF_ID_UPLIMIT ); - } + num = pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED ) + ? pref_int_get( PREF_KEY_UL_LIMIT ) + : -1; buf = ipc_mkint( con->ipc, &size, IPC_MSG_UPLIMIT, tag, num ); break; default: @@ -1052,7 +1047,7 @@ smsg_int( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) switch( id ) { case IPC_MSG_AUTOMAP: - tr_core_set_pref_bool( srv->core, PREF_ID_NAT, val->val.i ); + tr_core_set_pref_bool( srv->core, PREF_KEY_NAT, val->val.i ); break; case IPC_MSG_AUTOSTART: simpleresp( con, tag, IPC_MSG_BAD ); @@ -1060,33 +1055,29 @@ smsg_int( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) case IPC_MSG_DOWNLIMIT: if( 0 > val->val.i ) { - tr_core_set_pref_bool( srv->core, PREF_ID_USEDOWNLIMIT, - FALSE ); + tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 0 ); } else { - tr_core_set_pref_int( srv->core, PREF_ID_DOWNLIMIT, - val->val.i ); - tr_core_set_pref_bool( srv->core, PREF_ID_USEDOWNLIMIT, TRUE ); + tr_core_set_pref_int( srv->core, PREF_KEY_DL_LIMIT, val->val.i ); + tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 1 ); } break; case IPC_MSG_PEX: - tr_core_set_pref_bool( srv->core, PREF_ID_PEX, val->val.i ); + tr_core_set_pref_bool( srv->core, PREF_KEY_PEX, val->val.i ); break; case IPC_MSG_PORT: - tr_core_set_pref_int( srv->core, PREF_ID_PORT, val->val.i ); + tr_core_set_pref_int( srv->core, PREF_KEY_PORT, val->val.i ); break; case IPC_MSG_UPLIMIT: if( 0 > val->val.i ) { - tr_core_set_pref_bool( srv->core, PREF_ID_USEUPLIMIT, - FALSE ); + tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 0 ); } else { - tr_core_set_pref_int( srv->core, PREF_ID_UPLIMIT, - val->val.i ); - tr_core_set_pref_bool( srv->core, PREF_ID_USEUPLIMIT, TRUE ); + tr_core_set_pref_int( srv->core, PREF_KEY_UL_LIMIT, val->val.i ); + tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 1 ); } break; default: @@ -1110,7 +1101,7 @@ smsg_str( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) switch( id ) { case IPC_MSG_DIR: - tr_core_set_pref( srv->core, PREF_ID_DIR, val->val.s.s ); + tr_core_set_pref( srv->core, PREF_KEY_DIR_DEFAULT, val->val.s.s ); break; default: g_assert_not_reached(); diff --git a/gtk/main.c b/gtk/main.c index d3b59a6c3..71d1a0338 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -105,7 +105,7 @@ struct cbdata { TrCore * core; GtkWidget * icon; GtkWidget * msgwin; - TrPrefs * prefs; + GtkWidget * prefs; guint timer; gboolean closing; GList * errqueue; @@ -156,7 +156,7 @@ corepromptdata( TrCore *, uint8_t *, size_t, gboolean, gpointer ); static void readinitialprefs( struct cbdata * cbdata ); static void -prefschanged( TrCore * core, int id, gpointer data ); +prefschanged( TrCore * core, const char * key, gpointer data ); static void setpex( tr_torrent * tor, void * arg ); static gboolean @@ -244,12 +244,7 @@ main( int argc, char ** argv ) mainwind = GTK_WINDOW( tr_window_new( myUIManager ) ); /* try to load prefs and saved state */ - cf_loadprefs( &err ); - if( NULL != err ) - { - errmsg( mainwind, "%s", err ); - g_free( err ); - } + tr_prefs_init_global( ); state = cf_loadstate( &err ); if( NULL != err ) { @@ -428,7 +423,7 @@ appsetup( TrWindow * wind, GList * args, if( NULL != args ) { - action = toraddaction( tr_prefs_get( PREF_ID_ADDIPC ) ); + action = tr_prefs_get_action( PREF_KEY_ADDIPC ); tr_core_add_list( cbdata->core, args, action, paused ); } tr_core_torrents_added( cbdata->core ); @@ -659,7 +654,7 @@ gotdrag(GtkWidget *widget SHUTUP, GdkDragContext *dc, gint x SHUTUP, /* try to add any torrents we found */ if( NULL != paths ) { - action = toraddaction( tr_prefs_get( PREF_ID_ADDSTD ) ); + action = tr_prefs_get_action( PREF_KEY_ADDSTD ); tr_core_add_list( data->core, paths, action, FALSE ); tr_core_torrents_added( data->core ); g_list_free(paths); @@ -742,87 +737,72 @@ corepromptdata( TrCore * core, uint8_t * data, size_t size, static void readinitialprefs( struct cbdata * cbdata ) { - int prefs[] = + size_t i; + const char * keys[] = { - PREF_ID_PORT, - PREF_ID_DOWNLIMIT, - PREF_ID_USEDOWNLIMIT, - PREF_ID_UPLIMIT, - PREF_ID_USEUPLIMIT, - PREF_ID_NAT, - PREF_ID_ICON, - PREF_ID_PEX, + PREF_KEY_PORT, + PREF_KEY_DL_LIMIT_ENABLED, + PREF_KEY_DL_LIMIT, + PREF_KEY_UL_LIMIT_ENABLED, + PREF_KEY_UL_LIMIT, + PREF_KEY_NAT, + PREF_KEY_PEX, + PREF_KEY_SYSTRAY }; - int ii; - for( ii = 0; ALEN( prefs ) > ii; ii++ ) - { - prefschanged( NULL, prefs[ii], cbdata ); - } + for( i=0; icore ); - gboolean boolval; - switch( id ) + if( !strcmp( key, PREF_KEY_PORT ) ) { - case PREF_ID_PORT: - tr_setBindPort( tr, tr_prefs_get_int_with_default( id ) ); - break; - - case PREF_ID_USEDOWNLIMIT: - tr_setUseGlobalSpeedLimit( tr, TR_DOWN, - tr_prefs_get_bool_with_default( PREF_ID_USEDOWNLIMIT ) ); - break; - - case PREF_ID_DOWNLIMIT: - tr_setGlobalSpeedLimit( tr, TR_DOWN, - tr_prefs_get_int_with_default( PREF_ID_DOWNLIMIT ) ); - break; - - case PREF_ID_USEUPLIMIT: - tr_setUseGlobalSpeedLimit( tr, TR_UP, - tr_prefs_get_bool_with_default( PREF_ID_USEUPLIMIT ) ); - break; - - case PREF_ID_UPLIMIT: - tr_setGlobalSpeedLimit( tr, TR_UP, - tr_prefs_get_int_with_default( PREF_ID_UPLIMIT ) ); - break; - - case PREF_ID_NAT: - tr_natTraversalEnable( tr, tr_prefs_get_bool_with_default( id ) ); - break; - - case PREF_ID_ICON: - if( tr_prefs_get_bool_with_default( id ) ) - { - makeicon( cbdata ); - } - else if( NULL != cbdata->icon ) - { -g_message ("foo"); - g_object_unref( cbdata->icon ); - cbdata->icon = NULL; - } - break; - - case PREF_ID_PEX: - boolval = tr_prefs_get_bool_with_default( id ); - tr_torrentIterate( tr, setpex, &boolval ); - break; - - case PREF_ID_DIR: - case PREF_ID_ASKDIR: - case PREF_ID_ADDSTD: - case PREF_ID_ADDIPC: - case PREF_ID_MSGLEVEL: - case PREF_MAX_ID: - break; + const int port = pref_int_get( key ); + tr_setBindPort( tr, port ); + } + else if( !strcmp( key, PREF_KEY_DL_LIMIT_ENABLED ) ) + { + const gboolean b = pref_flag_get( key ); + tr_setUseGlobalSpeedLimit( tr, TR_DOWN, b ); + } + else if( !strcmp( key, PREF_KEY_DL_LIMIT ) ) + { + const int limit = pref_int_get( key ); + tr_setGlobalSpeedLimit( tr, TR_DOWN, limit ); + } + else if( !strcmp( key, PREF_KEY_UL_LIMIT_ENABLED ) ) + { + const gboolean b = pref_flag_get( key ); + tr_setUseGlobalSpeedLimit( tr, TR_UP, b ); + } + else if( !strcmp( key, PREF_KEY_UL_LIMIT ) ) + { + const int limit = pref_int_get( key ); + tr_setGlobalSpeedLimit( tr, TR_UP, limit ); + } + else if( !strcmp( key, PREF_KEY_NAT ) ) + { + const gboolean enabled = pref_flag_get( key ); + tr_natTraversalEnable( tr, enabled ); + } + else if( !strcmp( key, PREF_KEY_SYSTRAY ) ) + { + if( pref_flag_get( key ) ) { + makeicon( cbdata ); + } else if( cbdata->icon ) { + g_object_unref( cbdata->icon ); + cbdata->icon = NULL; + } + } + else if( !strcmp( key, PREF_KEY_PEX ) ) + { + gboolean enabled = pref_flag_get( key ); + tr_torrentIterate( tr, setpex, &enabled ); } } @@ -1064,8 +1044,7 @@ doAction ( const char * action_name, gpointer user_data ) { if( NULL == data->prefs ) { - data->prefs = tr_prefs_new_with_parent( G_OBJECT( data->core ), - data->wind ); + data->prefs = tr_prefs_dialog_new( G_OBJECT(data->core), data->wind ); g_signal_connect( data->prefs, "destroy", G_CALLBACK( gtk_widget_destroyed ), &data->prefs ); gtk_widget_show( GTK_WIDGET( data->prefs ) ); diff --git a/gtk/msgwin.c b/gtk/msgwin.c index 58e78d30a..3b4f38ddb 100644 --- a/gtk/msgwin.c +++ b/gtk/msgwin.c @@ -141,7 +141,7 @@ level_combo_changed_cb( GtkWidget * w, TrCore * core ) GtkTreeModel * m = gtk_combo_box_get_model( GTK_COMBO_BOX(w) ); gtk_tree_model_get( m, &iter, 1, &id, -1 ); tr_setMessageLevel( id ); - tr_core_set_pref_int( core, PREF_ID_MSGLEVEL, id ); + tr_core_set_pref_int( core, PREF_KEY_MSGLEVEL, id ); msgwin_update( ); } } @@ -259,8 +259,7 @@ msgwin_create( TrCore * core ) store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT); - curlevel = TR_MSG_INF; - tr_prefs_get_int( PREF_ID_MSGLEVEL, &curlevel ); + curlevel = pref_int_get( PREF_KEY_MSGLEVEL ); for( i=ii=0; iprefsig = g_signal_new( "prefs-changed", G_TYPE_FROM_CLASS( g_class ), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT ); + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING ); } void @@ -252,6 +252,8 @@ tr_core_dispose( GObject * obj ) } self->disposed = TRUE; + pref_save( NULL ); + #ifdef REFDBG fprintf( stderr, "core %p dispose\n", self ); #endif @@ -408,21 +410,22 @@ tr_core_load( TrCore * self, gboolean forcepaused ) int flags; int count = 0; tr_torrent ** torrents; - const char * destination; + char * path; TR_IS_CORE( self ); - destination = getdownloaddir( ); + path = getdownloaddir( ); flags = 0; if( forcepaused ) flags |= TR_FLAG_PAUSED; - torrents = tr_loadTorrents ( self->handle, destination, flags, &count ); + torrents = tr_loadTorrents ( self->handle, path, flags, &count ); for( i=0; ipromptsig, 0, paths, act, paused ); return 0; } - pref = getdownloaddir(); + dir = getdownloaddir(); count = 0; for( ; paths; paths=paths->next ) - if( tr_core_add_dir( self, paths->data, pref, act, paused ) ) + if( tr_core_add_dir( self, paths->data, dir, act, paused ) ) count++; + g_free( dir ); return count; } gboolean tr_core_add_data( TrCore * self, uint8_t * data, size_t size, gboolean paused ) { - const char * pref = tr_prefs_get( PREF_ID_ASKDIR ); - + gboolean ret; + char * path; TR_IS_CORE( self ); - if( strbool( pref ) ) + if( pref_flag_get( PREF_KEY_DIR_ASK ) ) { TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE ); g_signal_emit( self, class->promptdatasig, 0, data, size, paused ); return FALSE; } - return tr_core_add_data_dir( self, data, size, getdownloaddir(), paused ); + path = getdownloaddir( ); + ret = tr_core_add_data_dir( self, data, size, path, paused ); + g_free( path ); + return ret; } gboolean @@ -637,48 +643,48 @@ tr_core_quit( TrCore * self ) g_signal_emit( self, class->quitsig, 0 ); } -void -tr_core_set_pref( TrCore * self, int id, const char * val ) +/** +*** Prefs +**/ + +static void +commitPrefsChange( TrCore * self, const char * key ) { - const char * name, * old; - char * errstr; - TrCoreClass * class; + TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE ); + pref_save( NULL ); + g_signal_emit( self, class->prefsig, 0, key ); +} - TR_IS_CORE( self ); - - /* don't change anything if the new value is the same as the old one */ - name = tr_prefs_name( id ); - old = cf_getpref( name ); - if( !tr_strcmp( old, val ) ) - return; - - cf_setpref( name, val ); - - /* write prefs to disk */ - cf_saveprefs( &errstr ); - if( NULL != errstr ) +void +tr_core_set_pref( TrCore * self, const char * key, const char * newval ) +{ + char * oldval = pref_string_get( key ); + if( tr_strcmp( oldval, newval ) ) { - tr_core_errsig( self, TR_CORE_ERR_SAVE_STATE, errstr ); - g_free( errstr ); + pref_string_set( key, newval ); + commitPrefsChange( self, key ); } - - /* signal a pref change */ - class = g_type_class_peek( TR_CORE_TYPE ); - g_signal_emit( self, class->prefsig, 0, id ); + g_free( oldval ); } void -tr_core_set_pref_bool( TrCore * self, int id, gboolean val ) +tr_core_set_pref_bool( TrCore * self, const char * key, gboolean newval ) { - tr_core_set_pref( self, id, ( val ? "yes" : "no" ) ); + const gboolean oldval = pref_flag_get( key ); + if( oldval != newval ) + { + pref_flag_set( key, newval ); + commitPrefsChange( self, key ); + } } void -tr_core_set_pref_int( TrCore * self, int id, int val ) +tr_core_set_pref_int( TrCore * self, const char * key, int newval ) { - char buf[32]; - - g_snprintf( buf, sizeof buf, "%i", val ); - - tr_core_set_pref( self, id, buf ); + const int oldval = pref_int_get( key ); + if( oldval != newval ) + { + pref_int_set( key, newval ); + commitPrefsChange( self, key ); + } } diff --git a/gtk/tr_core.h b/gtk/tr_core.h index fed1d735c..d5d70df97 100644 --- a/gtk/tr_core.h +++ b/gtk/tr_core.h @@ -172,17 +172,17 @@ tr_core_quit( TrCore * self ); /* Set a preference value, save the prefs file, and emit the "prefs-changed" signal */ void -tr_core_set_pref( TrCore * self, int id, const char * val ); +tr_core_set_pref( TrCore * self, const char * key, const char * val ); /* Set a boolean preference value, save the prefs file, and emit the "prefs-changed" signal */ void -tr_core_set_pref_bool( TrCore * self, int id, gboolean val ); +tr_core_set_pref_bool( TrCore * self, const char * key, gboolean val ); /* Set an integer preference value, save the prefs file, and emit the "prefs-changed" signal */ void -tr_core_set_pref_int( TrCore * self, int id, int val ); +tr_core_set_pref_int( TrCore * self, const char * key, int val ); /* column names for the model used to store torrent information */ /* keep this in sync with the type array in tr_core_init() in tr_core.c */ diff --git a/gtk/tr_prefs.c b/gtk/tr_prefs.c index 28be04539..d67d07a47 100644 --- a/gtk/tr_prefs.c +++ b/gtk/tr_prefs.c @@ -1,1023 +1,258 @@ -/****************************************************************************** - * $Id$ +/* + * This file Copyright (C) 2007 Charles Kerr * - * Copyright (c) 2005-2007 Transmission authors and contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id:$ + */ -#include -#include -#include - -#include #include - +#include #include - #include "conf.h" -#include "tr_icon.h" +#include "hig.h" #include "tr_core.h" #include "tr_prefs.h" -#include "tr_torrent.h" #include "util.h" -/* used for g_object_set/get_data */ -#define PREF_CHECK_LINK "tr-prefs-check-link-thingy" -#define PREF_SPIN_LAST "tr-prefs-spinbox-last-val" - -/* convenience macros for saving pref id on a widget */ -#define SETPREFID( wid, id ) \ - ( g_object_set_data( G_OBJECT( (wid) ), "tr-prefs-id", \ - GINT_TO_POINTER( (id) + 1 ) ) ) -#define GETPREFID( wid, id ) \ - do \ - { \ - (id) = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( (wid) ), \ - "tr-prefs-id" ) ); \ - g_assert( 0 < (id) ); \ - (id)--; \ - } \ - while( 0 ) - -enum +/** + * This is where we initialize the preferences file with the default values. + * If you add a new preferences key, you /must/ add a default value here. + */ +void +tr_prefs_init_global( void ) { - PROP_PARENT = 1, - PROP_CORE -}; + pref_flag_set_default ( PREF_KEY_DL_LIMIT_ENABLED, FALSE ); + pref_int_set_default ( PREF_KEY_DL_LIMIT, 100 ); + pref_flag_set_default ( PREF_KEY_UL_LIMIT_ENABLED, FALSE ); + pref_int_set_default ( PREF_KEY_UL_LIMIT, 50 ); -#define PTYPE( id ) \ - ( G_TYPE_NONE == defs[(id)]._type ? \ - defs[(id)].typefunc() : defs[(id)]._type ) + pref_flag_set_default ( PREF_KEY_DIR_ASK, FALSE ); + pref_string_set_default ( PREF_KEY_DIR_DEFAULT, g_get_home_dir() ); -/* please keep this in sync with the enum in tr_prefs.c */ -/* don't forget defs_int, defs_bool, and defs_file too */ -static struct -{ - char * name; - GType _type; /* don't access this directly, use PTYPE() */ - enum { PR_ENABLED, PR_DISABLED, PR_SKIP } status; - GType (*typefunc)(void); - const char * label; - const char * tip; -} -defs[] = -{ - /* PREF_ID_USEDOWNLIMIT */ - { "use-download-limit", G_TYPE_BOOLEAN, PR_ENABLED, NULL, - N_("_Limit download speed"), - N_("Restrict the download rate") }, + pref_int_set_default ( PREF_KEY_PORT, TR_DEFAULT_PORT ); - /* PREF_ID_DOWNLIMIT */ - { "download-limit", G_TYPE_INT, PR_ENABLED, NULL, - N_("Maximum _download speed:"), - N_("Speed in KiB/sec for restricted download rate") }, + pref_flag_set_default ( PREF_KEY_NAT, TRUE ); + pref_flag_set_default ( PREF_KEY_PEX, TRUE ); + pref_flag_set_default ( PREF_KEY_SYSTRAY, TRUE ); + pref_flag_set_default ( PREF_KEY_ASKQUIT, TRUE ); - /* PREF_ID_USEUPLIMIT */ - { "use-upload-limit", G_TYPE_BOOLEAN, PR_ENABLED, NULL, - N_("Li_mit upload speed"), - N_("Restrict the upload rate") }, + pref_string_set_default ( PREF_KEY_ADDSTD, toractionname(TR_TOR_COPY) ); + pref_string_set_default ( PREF_KEY_ADDIPC, toractionname(TR_TOR_COPY) ); - /* PREF_ID_UPLIMIT */ - { "upload-limit", G_TYPE_INT, PR_ENABLED, NULL, - N_("Maximum _upload speed:"), - N_("Speed in KiB/sec for restricted upload rate") }, + pref_int_set_default ( PREF_KEY_MSGLEVEL, TR_MSG_INF ); - /* PREF_ID_ASKDIR */ - { "ask-download-directory", G_TYPE_BOOLEAN, PR_ENABLED, NULL, - N_("Al_ways prompt for download directory"), - N_("When adding a torrent, always prompt for a directory to download data files into") }, - - /* PREF_ID_DIR */ - { "download-directory", G_TYPE_NONE, PR_ENABLED, - gtk_file_chooser_get_type, - N_("Download di_rectory:"), - N_("Destination directory for downloaded data files") }, - - /* PREF_ID_PORT */ - { "listening-port", G_TYPE_INT, PR_ENABLED, NULL, - N_("Listening _port:"), - N_("TCP port number to listen for peer connections") }, - - /* PREF_ID_NAT */ - { "use-nat-traversal", G_TYPE_BOOLEAN, PR_ENABLED, NULL, - N_("Au_tomatic port mapping via NAT-PMP or UPnP"), - N_("Attempt to bypass NAT or firewall to allow incoming peer connections") }, - - /* PREF_ID_PEX */ - { "use-peer-exchange", G_TYPE_BOOLEAN, PR_ENABLED, NULL, - N_("Use peer _exchange if possible"), - N_("Perform Azureus or \xc2\xb5Torrent compatible peer exchange with any peers which support it") }, - - /* PREF_ID_ICON */ - { "use-tray-icon", G_TYPE_BOOLEAN, - ( status_icon_supported() ? PR_ENABLED : PR_DISABLED ), NULL, - N_("Display an _icon in the system tray"), - N_("Use a system tray / dock / notification area icon") }, - - /* PREF_ID_ASKQUIT */ - { "ask-quit", G_TYPE_BOOLEAN, PR_ENABLED, NULL, - N_("Confirm _quit"), - N_("Prompt for confirmation when quitting") }, - - /* PREF_ID_ADDSTD */ - { "add-behavior-standard", G_TYPE_NONE, PR_ENABLED, - gtk_combo_box_get_type, - N_("For torrents added _normally:"), - N_("Torrent files added via the toolbar, popup menu, and drag-and-drop") }, - - /* PREF_ID_ADDIPC */ - { "add-behavior-ipc", G_TYPE_NONE, PR_ENABLED, - gtk_combo_box_get_type, - N_("For torrents added e_xternally\n(via the command-line):"), - N_("For torrents added via the command-line only") }, - - /* PREF_ID_MSGLEVEL */ - { "message-level", G_TYPE_INT, PR_SKIP, NULL, NULL, NULL }, -}; - -static struct -{ - long min; - long max; - long def; -} -defs_int[] = -{ - { 0, 0, 0 }, - /* PREF_ID_DOWNLIMIT */ - { 0, G_MAXLONG, 100 }, - { 0, 0, 0 }, - /* PREF_ID_UPLIMIT */ - { 0, G_MAXLONG, 20 }, - { 0, 0, 0 }, { 0, 0, 0 }, - /* PREF_ID_PORT */ - { 1, 0xffff, TR_DEFAULT_PORT }, -}; - -static struct -{ - gboolean def; - int link; - gboolean enables; -} -defs_bool[] = -{ - /* PREF_ID_USEDOWNLIMIT */ - { FALSE, PREF_ID_DOWNLIMIT, TRUE }, - { FALSE, -1, FALSE }, - /* PREF_ID_USEUPLIMIT */ - { FALSE, PREF_ID_UPLIMIT, TRUE }, - { FALSE, -1, FALSE }, - /* PREF_ID_ASKDIR */ - { FALSE, PREF_ID_DIR, FALSE }, - { FALSE, -1, FALSE }, { FALSE, -1, FALSE }, - /* PREF_ID_NAT */ - { TRUE, -1, FALSE }, - /* PREF_ID_PEX */ - { TRUE, -1, FALSE }, - /* PREF_ID_ICON */ - { TRUE, -1, FALSE }, - /* PREF_ID_ASKQUIT */ - { TRUE, -1, FALSE }, -}; - -static struct -{ - const char * title; - GtkFileChooserAction act; - const char * (*getdef)(void); -} -defs_file[] = -{ - { NULL, 0, NULL }, { NULL, 0, NULL }, { NULL, 0, NULL }, - { NULL, 0, NULL }, { NULL, 0, NULL }, - /* PREF_ID_DIR */ - { N_("Choose a download directory"), - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - getdownloaddir }, -}; - -struct checkctl -{ - GtkToggleButton * check; - GtkWidget * wids[2]; - gboolean enables; -}; - -static void -tr_prefs_init( GTypeInstance * instance, gpointer g_class ); -static void -tr_prefs_set_property( GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec ); -static void -tr_prefs_get_property( GObject * object, guint property_id, - GValue * value, GParamSpec * pspec); -static void -tr_prefs_class_init( gpointer g_class, gpointer g_class_data ); -static void -tr_prefs_dispose( GObject * obj ); -static void -gotresp( GtkWidget * widget, int resp, gpointer data ); -static int -countprefs( void ); -static void -makelinks( struct checkctl ** links ); -static void -filllinks( int id, GtkWidget * wid1, GtkWidget * wid2, - struct checkctl ** links ); -static void -pokelink( struct checkctl * link ); -static void -addwidget( TrPrefs * self, int id, GtkTable * table, int off, - GtkTooltips * tips, struct checkctl ** links, GtkWidget ** wids ); -static GtkWidget * -tipbox( GtkWidget * widget, GtkTooltips * tips, const char * tip ); -static void -addwid_bool( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, struct checkctl ** links, GtkWidget ** wids ); -static void -checkclick( GtkWidget * widget, gpointer data ); -static void -addwid_int( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids ); -static gboolean -spinfocus( GtkWidget * widget, GdkEventFocus *event, gpointer data ); -static void -spindie( GtkWidget * widget, gpointer data ); -static void -addwid_file( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids ); -static void -filechosen( GtkWidget * widget, gpointer data ); -static GtkTreeModel * -makecombomodel( void ); -static void -addwid_combo( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids ); -static void -setcombosel( GtkTreeModel * model, GtkComboBox * combo, int id ); -static void -combochosen( GtkWidget * widget, gpointer data ); -static void -prefschanged( TrCore * core, int id, gpointer data ); - -GType -tr_prefs_get_type( void ) -{ - static GType type = 0; - - if( 0 == type ) - { - static const GTypeInfo info = - { - sizeof( TrPrefsClass ), - NULL, /* base_init */ - NULL, /* base_finalize */ - tr_prefs_class_init, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof( TrPrefs ), - 0, /* n_preallocs */ - tr_prefs_init, /* instance_init */ - NULL, - }; - type = g_type_register_static( GTK_TYPE_DIALOG, "TrPrefs", &info, 0 ); - } - - return type; + pref_save( NULL ); } -static void -tr_prefs_class_init( gpointer g_class, gpointer g_class_data SHUTUP ) -{ - GObjectClass * gobject_class; - GParamSpec * pspec; - - gobject_class = G_OBJECT_CLASS( g_class ); - gobject_class->set_property = tr_prefs_set_property; - gobject_class->get_property = tr_prefs_get_property; - gobject_class->dispose = tr_prefs_dispose; - - pspec = g_param_spec_object( "parent", "Parent", - "The parent GtkWindow.", - GTK_TYPE_WINDOW, G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_PARENT, pspec ); - - pspec = g_param_spec_object( "core", "Parent", - "The TrCore object.", - TR_CORE_TYPE, G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_CORE, pspec ); -} - -static void -tr_prefs_init( GTypeInstance * instance, gpointer g_class SHUTUP ) -{ - struct checkctl * links[ ALEN( defs_bool ) ]; - TrPrefs * self = ( TrPrefs * )instance; - char * title; - GtkWidget * table; - GtkTooltips * tips; - int rows, ii, off; - - self->combomodel = makecombomodel(); - self->core = NULL; - self->prefwids = g_new0( GtkWidget *, PREF_MAX_ID ); - self->disposed = FALSE; - self->fileselhack = FALSE; - - gtk_window_set_role( GTK_WINDOW( self ), "tr-prefs" ); - title = g_strdup_printf( _("%s Preferences"), g_get_application_name() ); - gtk_window_set_title( GTK_WINDOW( self ), title ); - g_free( title ); - gtk_dialog_set_has_separator( GTK_DIALOG( self ), FALSE ); - gtk_dialog_add_button( GTK_DIALOG( self ), GTK_STOCK_CLOSE, - GTK_RESPONSE_CLOSE ); - gtk_widget_set_name( GTK_WIDGET( self ), "TransmissionDialog"); - gtk_dialog_set_default_response( GTK_DIALOG( self ), GTK_RESPONSE_CLOSE ); - gtk_container_set_border_width( GTK_CONTAINER( self ), 6 ); - gtk_window_set_resizable( GTK_WINDOW( self ), FALSE ); - - rows = countprefs(); - table = gtk_table_new( rows, 2, FALSE ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 8 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 8 ); - - tips = gtk_tooltips_new(); - g_object_ref( tips ); - gtk_object_sink( GTK_OBJECT( tips ) ); - gtk_tooltips_enable( tips ); - g_signal_connect_swapped( self, "destroy", - G_CALLBACK( g_object_unref ), tips ); - - memset( links, 0, sizeof( links ) ); - makelinks( links ); - off = 0; - for( ii = 0; PREF_MAX_ID > ii; ii++ ) - { - if( PR_SKIP != defs[ii].status ) - { - addwidget( self, ii, GTK_TABLE( table ), off, tips, links, - self->prefwids ); - off++; - } - } - g_assert( rows == off ); - for( ii = 0; ALEN( links ) > ii; ii++ ) - { - g_assert( NULL == links[ii] || NULL != links[ii]->check ); - if( NULL != links[ii] ) - { - pokelink( links[ii] ); - } - } - - gtk_box_pack_start_defaults( GTK_BOX( GTK_DIALOG( self )->vbox ), table ); - g_signal_connect( self, "response", G_CALLBACK( gotresp ), NULL ); - gtk_widget_show_all( table ); -} - -static void -tr_prefs_set_property( GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - TrPrefs * self = ( TrPrefs * )object; - - if( self->disposed ) - { - return; - } - - switch( property_id ) - { - case PROP_PARENT: - gtk_window_set_transient_for( GTK_WINDOW( self ), - g_value_get_object( value ) ); - break; - case PROP_CORE: - if( NULL != self->core ) - { - g_signal_handler_disconnect( self->core, self->sigid ); - g_object_unref( self->core ); - } - self->core = g_value_get_object( value ); - if( NULL != self->core ) - { - g_object_ref( self->core ); - self->sigid = g_signal_connect( self->core, "prefs-changed", - G_CALLBACK( prefschanged ), - self ); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec ); - break; - } -} - -static void -tr_prefs_get_property( GObject * object, guint property_id, - GValue * value, GParamSpec * pspec ) -{ - TrPrefs * self = ( TrPrefs * )object; - GtkWindow * trans; - - if( self->disposed ) - { - return; - } - - switch( property_id ) - { - case PROP_PARENT: - trans = gtk_window_get_transient_for( GTK_WINDOW( self ) ); - g_value_set_object( value, trans ); - break; - case PROP_CORE: - g_value_set_object( value, self->core ); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec ); - break; - } -} - -static void -tr_prefs_dispose( GObject * obj ) -{ - TrPrefs * self = ( TrPrefs * )obj; - GObjectClass * parent; - - if( self->disposed ) - { - return; - } - self->disposed = TRUE; - - g_object_unref( self->combomodel ); - - if( NULL != self->core ) - { - g_signal_handler_disconnect( self->core, self->sigid ); - g_object_unref( self->core ); - } - - g_free( self->prefwids ); - - /* Chain up to the parent class */ - parent = g_type_class_peek( g_type_parent( TR_PREFS_TYPE ) ); - parent->dispose( obj ); -} - -TrPrefs * -tr_prefs_new( GObject * core ) -{ - return g_object_new( TR_PREFS_TYPE, "core", core, NULL ); -} - -TrPrefs * -tr_prefs_new_with_parent( GObject * core, GtkWindow * parent ) -{ - return g_object_new( TR_PREFS_TYPE, "core", core, "parent", parent, NULL ); -} - -const char * -tr_prefs_name( int id ) -{ - g_assert( 0 <= id && PREF_MAX_ID > id && ALEN( defs ) == PREF_MAX_ID ); - return defs[id].name; -} - -gboolean -tr_prefs_get_int( int id, int * val ) -{ - const char * str; - char * end; - int ret; - - str = tr_prefs_get( id ); - if( NULL == str || '\0' == *str ) - { - return FALSE; - } - - errno = 0; - ret = strtol( str, &end, 10 ); - if( 0 != errno || NULL == end || '\0' != *end ) - { - return FALSE; - } - *val = ret; - return TRUE; -} - -gboolean -tr_prefs_get_bool( int id, gboolean * val ) -{ - const char * str; - - str = tr_prefs_get( id ); - if( NULL == str ) - { - return FALSE; - } - *val = strbool( str ); - return TRUE; -} +/** +*** +**/ int -tr_prefs_get_int_with_default( int id ) +tr_prefs_get_action( const char * key ) { - int ret; - - g_assert( 0 <= id && ALEN( defs ) > id && - G_TYPE_INT == PTYPE( id ) && ALEN( defs_int ) > id ); - - if( tr_prefs_get_int( id, &ret ) ) - { - return ret; - } - return defs_int[id].def; -} - -gboolean -tr_prefs_get_bool_with_default( int id ) -{ - gboolean ret; - - g_assert( 0 <= id && ALEN( defs ) > id && - G_TYPE_BOOLEAN == PTYPE( id ) && ALEN( defs_bool ) > id ); - - if( tr_prefs_get_bool( id, &ret ) ) - { - return ret; - } - return defs_bool[id].def; - -} - -static void -gotresp( GtkWidget * widget, int resp SHUTUP, gpointer data SHUTUP ) -{ - gtk_widget_destroy( widget ); -} - -static int -countprefs( void ) -{ - int ii, ret; - - g_assert( ALEN( defs ) == PREF_MAX_ID ); - ret = 0; - for( ii = 0; PREF_MAX_ID > ii; ii++ ) - { - if( PR_SKIP != defs[ii].status ) - { - ret++; - } - } - + char * val = pref_string_get( key ); + const int ret = toraddaction( val ); + g_free( val ); return ret; } -static void -makelinks( struct checkctl ** links ) +void +tr_prefs_set_action( const char * key, int action ) { - int ii; + pref_string_set( key, toractionname(action) ); +} - g_assert( ALEN( defs ) == PREF_MAX_ID ); - for( ii = 0; PREF_MAX_ID > ii; ii++ ) - { - if( PR_SKIP == defs[ii].status || G_TYPE_BOOLEAN != PTYPE( ii ) ) - { - continue; - } - g_assert( ALEN( defs_bool ) > ii ); - if( 0 <= defs_bool[ii].link ) - { - links[ii] = g_new0( struct checkctl, 1 ); - } - } +/** +*** +**/ + +#define PREFS_KEY "prefs-key" + +static void +response_cb( GtkDialog * dialog, int response UNUSED, gpointer unused UNUSED ) +{ + gtk_widget_destroy( GTK_WIDGET(dialog) ); } static void -filllinks( int id, GtkWidget * wid1, GtkWidget * wid2, - struct checkctl ** links ) +toggled_cb( GtkToggleButton * w, gpointer core ) { - int ii; + const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY ); + const gboolean flag = gtk_toggle_button_get_active( w ); + tr_core_set_pref_bool( TR_CORE(core), key, flag ); +} - g_assert( ALEN( defs ) >= ALEN( defs_bool ) ); - for( ii = 0; ALEN( defs_bool) > ii; ii++ ) - { - if( NULL == links[ii] ) - { - g_assert( PR_SKIP == defs[ii].status || - G_TYPE_BOOLEAN != PTYPE( ii ) || - 0 > defs_bool[ii].link ); - } - else - { - g_assert( PR_SKIP != defs[ii].status && - G_TYPE_BOOLEAN == PTYPE( ii ) && - 0 <= defs_bool[ii].link ); - if( id == defs_bool[ii].link ) - { - links[ii]->wids[0] = wid1; - links[ii]->wids[1] = wid2; - } - } - } +static GtkWidget* +new_check_button( const char * mnemonic, const char * key, gpointer core ) +{ + GtkWidget * w = gtk_check_button_new_with_mnemonic( mnemonic ); + g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w), pref_flag_get(key) ); + g_signal_connect( w, "toggled", G_CALLBACK(toggled_cb), core ); + return w; } static void -pokelink( struct checkctl * link ) +spun_cb( GtkSpinButton * w, gpointer core ) { - gboolean active; + const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY ); + const int value = gtk_spin_button_get_value_as_int( w ); + tr_core_set_pref_int( TR_CORE(core), key, value ); +} - active = gtk_toggle_button_get_active( link->check ); - active = ( link->enables ? active : !active ); - gtk_widget_set_sensitive( link->wids[0], active ); - gtk_widget_set_sensitive( link->wids[1], active ); +static GtkWidget* +new_spin_button( const char * key, gpointer core, int low, int high ) +{ + GtkWidget * w = gtk_spin_button_new_with_range( low, high, 1 ); + g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free ); + gtk_spin_button_set_digits( GTK_SPIN_BUTTON(w), 0 ); + gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), pref_int_get(key) ); + g_signal_connect( w, "value-changed", G_CALLBACK(spun_cb), core ); + return w; } static void -addwidget( TrPrefs * self, int id, GtkTable * table, int off, - GtkTooltips * tips, struct checkctl ** links, GtkWidget ** widgets ) +chosen_cb( GtkFileChooser * w, gpointer core ) { - GType type; - GtkWidget * add1, * add2; - - g_assert( ALEN( defs ) > id ); - - type = PTYPE( id ); - add1 = NULL; - add2 = NULL; - if( G_TYPE_BOOLEAN == type ) - { - addwid_bool( self, id, tips, &add1, links, widgets ); - } - else if( G_TYPE_INT == type ) - { - addwid_int( self, id, tips, &add1, &add2, widgets ); - } - else if( GTK_TYPE_FILE_CHOOSER == type ) - { - addwid_file( self, id, tips, &add1, &add2, widgets ); - } - else if( GTK_TYPE_COMBO_BOX == type ) - { - addwid_combo( self, id, tips, &add1, &add2, widgets ); - } - else - { - g_assert_not_reached(); - } - - g_assert( NULL != add1 ); - filllinks( id, add1, add2, links ); - if( NULL == add2 ) - { - gtk_table_attach_defaults( table, add1, 0, 2, off, off + 1 ); - } - else - { - gtk_table_attach_defaults( table, add1, 0, 1, off, off + 1 ); - gtk_table_attach_defaults( table, add2, 1, 2, off, off + 1 ); - } - if( PR_DISABLED == defs[id].status ) - { - gtk_widget_set_sensitive( add1, FALSE ); - if( NULL != add2 ) - { - gtk_widget_set_sensitive( add2, FALSE ); - } - } + const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY ); + char * value = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(w) ); + tr_core_set_pref( TR_CORE(core), key, value ); + g_free( value ); } -/* wrap a widget in an event box with a tooltip */ -static GtkWidget * -tipbox( GtkWidget * widget, GtkTooltips * tips, const char * tip ) +static GtkWidget* +new_path_chooser_button( const char * key, gpointer core ) { - GtkWidget * box; - - box = gtk_event_box_new(); - gtk_container_add( GTK_CONTAINER( box ), widget ); - gtk_tooltips_set_tip( tips, box, tip, "" ); - - return box; + GtkWidget * w = gtk_file_chooser_button_new( "asdf", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ); + char * path = pref_string_get( key ); + g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free ); + g_signal_connect( w, "selection-changed", G_CALLBACK(chosen_cb), core ); + gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(w), path ); + return w; } static void -addwid_bool( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, struct checkctl ** links, GtkWidget ** wids ) +action_cb( GtkComboBox * w, gpointer core ) { - GtkWidget * check; - gboolean active; - - g_assert( ALEN( defs ) > id && G_TYPE_BOOLEAN == PTYPE( id ) ); - check = gtk_check_button_new_with_mnemonic( gettext( defs[id].label ) ); - wids[id] = check; - gtk_tooltips_set_tip( tips, check, gettext( defs[id].tip ), "" ); - if( 0 > defs_bool[id].link ) + const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY ); + GtkTreeIter iter; + if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX(w), &iter ) ) { - g_assert( NULL == links[id] ); + int action; + GtkTreeModel * model = gtk_combo_box_get_model( GTK_COMBO_BOX(w) ); + gtk_tree_model_get( model, &iter, 1, &action, -1 ); + tr_core_set_pref( core, key, toractionname(action) ); } - else - { - links[id]->check = GTK_TOGGLE_BUTTON( check ); - links[id]->enables = defs_bool[id].enables; - g_object_set_data_full( G_OBJECT( check ), PREF_CHECK_LINK, - links[id], g_free ); - } - active = tr_prefs_get_bool_with_default( id ); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check ), active ); - SETPREFID( check, id ); - g_signal_connect( check, "clicked", G_CALLBACK( checkclick ), self ); - - *wid1 = check; } -static void -checkclick( GtkWidget * widget, gpointer data ) +static GtkWidget* +new_action_combo( const char * key, gpointer core ) { - TrPrefs * self; - struct checkctl * link; - int id; - gboolean active; + GtkTreeIter iter; + GtkCellRenderer * rend; + GtkListStore * model; + GtkWidget * w; - TR_IS_PREFS( data ); - self = TR_PREFS( data ); - link = g_object_get_data( G_OBJECT( widget ), PREF_CHECK_LINK ); - GETPREFID( widget, id ); - - if( NULL != link ) - { - pokelink( link ); - } - - active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( widget ) ); - tr_core_set_pref_bool( TR_CORE( self->core ), id, active ); -} - -static void -addwid_int( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids ) -{ - GtkWidget * spin, * label; - int val, * last; - - g_assert( ALEN( defs ) > id && G_TYPE_INT == PTYPE( id ) ); - spin = gtk_spin_button_new_with_range( defs_int[id].min, - defs_int[id].max, 1 ); - wids[id] = spin; - label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) ); - gtk_label_set_mnemonic_widget( GTK_LABEL( label ), spin ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 ); - gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin ), TRUE ); - gtk_tooltips_set_tip( tips, spin, gettext( defs[id].tip ), "" ); - val = tr_prefs_get_int_with_default( id ); - gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin ), val ); - last = g_new( int, 1 ); - *last = val; - g_object_set_data_full( G_OBJECT( spin ), PREF_SPIN_LAST, last, g_free ); - SETPREFID( spin, id ); - /* I don't trust that focus-out-event will always work, - so save pref on widget destruction too */ - g_signal_connect( spin, "focus-out-event", G_CALLBACK( spinfocus ), self ); - g_signal_connect( spin, "destroy", G_CALLBACK( spindie ), self ); - - *wid1 = tipbox( label, tips, gettext( defs[id].tip ) ); - *wid2 = spin; -} - -static gboolean -spinfocus( GtkWidget * widget, GdkEventFocus *event SHUTUP, gpointer data ) -{ - TrPrefs * self; - int * last, id, cur; - - TR_IS_PREFS( data ); - self = TR_PREFS( data ); - last = g_object_get_data( G_OBJECT( widget ), PREF_SPIN_LAST ); - GETPREFID( widget, id ); - cur = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( widget ) ); - - if( cur != *last ) - { - tr_core_set_pref_int( TR_CORE( self->core ), id, cur ); - *last = cur; - } - - /* continue propagating the event */ - return FALSE; -} - -static void -spindie( GtkWidget * widget, gpointer data ) -{ - spinfocus( widget, NULL, data ); -} - -static void -addwid_file( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids ) -{ - GtkWidget * file, * label; - const char * pref; - - g_assert( ALEN( defs ) > id && GTK_TYPE_FILE_CHOOSER == PTYPE( id ) ); - file = gtk_file_chooser_button_new( gettext( defs_file[id].title ), - defs_file[id].act ); - wids[id] = file; - label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) ); - gtk_label_set_mnemonic_widget( GTK_LABEL( label ), file ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 ); - pref = tr_prefs_get( id ); - if( NULL == pref ) - { - pref = defs_file[id].getdef(); - } - gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( file ), pref ); - SETPREFID( file, id ); - g_signal_connect( file, "selection-changed", - G_CALLBACK( filechosen ), self ); - - *wid1 = tipbox( label, tips, gettext( defs[id].tip ) ); - *wid2 = tipbox( file, tips, gettext( defs[id].tip ) ); -} - -static void -filechosen( GtkWidget * widget, gpointer data ) -{ - TrPrefs * self; - char * dir; - int id; - - TR_IS_PREFS( data ); - self = TR_PREFS( data ); - dir = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( widget ) ); - GETPREFID( widget, id ); - self->fileselhack = TRUE; - tr_core_set_pref( TR_CORE( self->core ), id, dir ); - self->fileselhack = FALSE; - g_free( dir ); -} - -static GtkTreeModel * -makecombomodel( void ) -{ - GtkListStore * list; - GtkTreeIter iter; - - /* create the model used by the two popup menus */ - list = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - gtk_list_store_append( list, &iter ); - gtk_list_store_set( list, &iter, 1, TR_TOR_LEAVE, 0, + model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 1, TR_TOR_LEAVE, 0, _("Use the torrent file where it is"), -1 ); - gtk_list_store_append( list, &iter ); - gtk_list_store_set( list, &iter, 1, TR_TOR_COPY, 0, + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 1, TR_TOR_COPY, 0, _("Keep a copy of the torrent file"), -1 ); - gtk_list_store_append( list, &iter ); - gtk_list_store_set( list, &iter, 1, TR_TOR_MOVE, 0, + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 1, TR_TOR_MOVE, 0, _("Keep a copy and remove the original"), -1 ); - return GTK_TREE_MODEL( list ); + w = gtk_combo_box_new_with_model( GTK_TREE_MODEL(model) ); + gtk_combo_box_set_active( GTK_COMBO_BOX(w), pref_int_get(key) ); + g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free ); + rend = gtk_cell_renderer_text_new( ); + gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(w), rend, TRUE ); + gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(w), rend, "text", 0 ); + g_signal_connect( w, "changed", G_CALLBACK(action_cb), core ); + + return w; } -static void -addwid_combo( TrPrefs * self, int id, GtkTooltips * tips, - GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids ) +GtkWidget * +tr_prefs_dialog_new( GObject * core, GtkWindow * parent ) { - GtkWidget * combo, * label; - GtkCellRenderer * rend; + int row = 0; + GtkWidget * t; + GtkWidget * w; + GtkWidget * l; + GtkWidget * dialog = gtk_dialog_new_with_buttons( _("Transmission: Preferences"), parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + NULL ); + gtk_window_set_role( GTK_WINDOW(dialog), "transmission-preferences-dialog" ); + g_signal_connect( dialog, "response", G_CALLBACK(response_cb), core ); - g_assert( ALEN( defs ) > id && GTK_TYPE_COMBO_BOX == PTYPE( id ) ); - combo = gtk_combo_box_new(); - wids[id] = combo; - label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) ); - gtk_label_set_mnemonic_widget( GTK_LABEL( label ), combo ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 ); - gtk_combo_box_set_model( GTK_COMBO_BOX( combo ), self->combomodel ); - rend = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( combo ), rend, TRUE ); - gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT( combo ), rend, "text", 0 ); + t = hig_workarea_create (); - setcombosel( self->combomodel, GTK_COMBO_BOX( combo ), id ); - SETPREFID( combo, id ); - g_signal_connect( combo, "changed", G_CALLBACK( combochosen ), self ); + hig_workarea_add_section_title (t, &row, _("Speed Limits")); + hig_workarea_add_section_spacer (t, row, 4); - *wid1 = tipbox( label, tips, gettext( defs[id].tip ) ); - *wid2 = tipbox( combo, tips, gettext( defs[id].tip ) ); -} - -static void -setcombosel( GtkTreeModel * model, GtkComboBox * combo, int id ) -{ - GtkTreeIter iter; - enum tr_torrent_action prefsact, modelact; - - prefsact = toraddaction( tr_prefs_get( id ) ); - if( gtk_tree_model_get_iter_first( model, &iter ) ) - { - do - { - gtk_tree_model_get( model, &iter, 1, &modelact, -1 ); - if( modelact == prefsact ) - { - gtk_combo_box_set_active_iter( combo, &iter ); - break; - } - } - while( gtk_tree_model_iter_next( model, &iter ) ); - } -} - -static void -combochosen( GtkWidget * widget, gpointer data ) -{ - TrPrefs * self; - GtkTreeIter iter; - GtkTreeModel * model; - enum tr_torrent_action action; - int id; - - TR_IS_PREFS( data ); - self = TR_PREFS( data ); - if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX( widget ), &iter ) ) - { - model = gtk_combo_box_get_model( GTK_COMBO_BOX( widget ) ); - gtk_tree_model_get( model, &iter, 1, &action, -1 ); - GETPREFID( widget, id ); - tr_core_set_pref( TR_CORE( self->core ), id, toractionname( action ) ); - } -} - -static void -prefschanged( TrCore * core SHUTUP, int id, gpointer data ) -{ - TrPrefs * prefs; - GtkWidget * wid; - gboolean boolval; - int intval; - const char * strval; - - TR_IS_PREFS( data ); - prefs = TR_PREFS( data ); - - g_assert( ALEN( defs ) > id && 0 <= id ); - - wid = prefs->prefwids[id]; - - if( G_TYPE_BOOLEAN == PTYPE( id ) ) - { - boolval = tr_prefs_get_bool_with_default( id ); - if( boolval != - gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( wid ) ) ) - { - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( wid ), boolval ); - } - } - else if( G_TYPE_INT == PTYPE( id ) ) - { - intval = tr_prefs_get_int_with_default( id ); - if( intval != - gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( wid ) ) ) - { - gtk_spin_button_set_value( GTK_SPIN_BUTTON( wid ), intval ); - } - } - else if( GTK_TYPE_FILE_CHOOSER == PTYPE( id ) ) - { - strval = tr_prefs_get( id ); - if( !prefs->fileselhack && strval != - gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( wid ) ) ) - { - gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( wid ), - strval ); - } - } - else if( GTK_TYPE_COMBO_BOX == PTYPE( id ) ) - { - setcombosel( prefs->combomodel, GTK_COMBO_BOX( wid ), id ); - } - else - { - g_assert_not_reached(); - } + w = new_check_button( _("_Limit Upload Speed"), PREF_KEY_UL_LIMIT_ENABLED, core ); + hig_workarea_add_wide_control( t, &row, w ); + + w = new_spin_button( PREF_KEY_UL_LIMIT, core, 20, INT_MAX ); + l = hig_workarea_add_row( t, &row, _("Maximum _Upload Speed (KiB/s)"), w, NULL ); + + w = new_check_button( _("Li_mit Download Speed"), PREF_KEY_DL_LIMIT_ENABLED, core ); + hig_workarea_add_wide_control( t, &row, w ); + + w = new_spin_button( PREF_KEY_DL_LIMIT, core, 1, INT_MAX ); + l = hig_workarea_add_row( t, &row, _("Maximum _Download Speed (KiB/s)"), w, NULL ); + + hig_workarea_add_section_divider( t, &row ); + hig_workarea_add_section_title (t, &row, _("Downloads")); + hig_workarea_add_section_spacer (t, row, 4); + + w = new_check_button( _("Al_ways prompt for download directory"), PREF_KEY_DIR_ASK, core ); + hig_workarea_add_wide_control( t, &row, w ); + + w = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core ); + l = hig_workarea_add_row( t, &row, _("Download Di_rectory"), w, NULL ); + + w = new_action_combo( PREF_KEY_ADDSTD, core ); + l = hig_workarea_add_row( t, &row, _("For torrents added _normally:"), w, NULL ); + + w = new_action_combo( PREF_KEY_ADDIPC, core ); + l = hig_workarea_add_row( t, &row, _("For torrents added from _command-line:"), w, NULL ); + + hig_workarea_add_section_divider( t, &row ); + hig_workarea_add_section_title (t, &row, _("Network")); + hig_workarea_add_section_spacer (t, row, 2); + + w = new_check_button( _("_Automatic Port Mapping via NAT-PMP or UPnP"), PREF_KEY_NAT, core ); + hig_workarea_add_wide_control( t, &row, w ); + + w = new_spin_button( PREF_KEY_PORT, core, 1, INT_MAX ); + l = hig_workarea_add_row( t, &row, _("Listening _Port"), w, NULL ); + + hig_workarea_add_section_divider( t, &row ); + hig_workarea_add_section_title (t, &row, _("Options")); + hig_workarea_add_section_spacer (t, row, 3); + + w = new_check_button( _("Use Peer _Exchange if Possible"), PREF_KEY_PEX, core ); + hig_workarea_add_wide_control( t, &row, w ); + + w = new_check_button( _("Display an Icon in the System _Tray"), PREF_KEY_SYSTRAY, core ); + hig_workarea_add_wide_control( t, &row, w ); + + w = new_check_button( _("Confirm _quit"), PREF_KEY_ASKQUIT, core ); + hig_workarea_add_wide_control( t, &row, w ); + + hig_workarea_finish (t, &row); + gtk_box_pack_start_defaults( GTK_BOX(GTK_DIALOG(dialog)->vbox), t ); + gtk_widget_show_all( GTK_DIALOG(dialog)->vbox ); + return dialog; } diff --git a/gtk/tr_prefs.h b/gtk/tr_prefs.h index 99f968db2..d2dd66924 100644 --- a/gtk/tr_prefs.h +++ b/gtk/tr_prefs.h @@ -1,116 +1,40 @@ -/****************************************************************************** - * $Id$ +/* + * This file Copyright (C) 2007 Charles Kerr * - * Copyright (c) 2007 Transmission authors and contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id:$ + */ #ifndef TR_PREFS_H #define TR_PREFS_H #include -#include "conf.h" +GtkWidget * tr_prefs_dialog_new( GObject * core, GtkWindow * parent ); -#define TR_PREFS_TYPE ( tr_prefs_get_type() ) +#define PREF_KEY_DL_LIMIT_ENABLED "download-limit-enabled" +#define PREF_KEY_DL_LIMIT "download-limit" +#define PREF_KEY_UL_LIMIT_ENABLED "upload-limit-enabled" +#define PREF_KEY_UL_LIMIT "upload-limit" +#define PREF_KEY_DIR_ASK "prompt-for-download-directory" +#define PREF_KEY_DIR_DEFAULT "default-download-directory" +#define PREF_KEY_ADDSTD "add-behavior-standard" +#define PREF_KEY_ADDIPC "add-behavior-ipc" +#define PREF_KEY_PORT "listening-port" +#define PREF_KEY_NAT "nat-traversal-enabled" +#define PREF_KEY_PEX "pex-enabled" +#define PREF_KEY_SYSTRAY "system-tray-icon-enabled" +#define PREF_KEY_ASKQUIT "prompt-before-exit" +#define PREF_KEY_MSGLEVEL "debug-message-level" -#define TR_PREFS( obj ) \ - ( G_TYPE_CHECK_INSTANCE_CAST( (obj), TR_PREFS_TYPE, TrPrefs ) ) +void tr_prefs_init_global( void ); -#define TR_PREFS_CLASS( class ) \ - ( G_TYPE_CHECK_CLASS_CAST( (class), TR_PREFS_TYPE, TrPrefsClass ) ) - -#define TR_IS_PREFS( obj ) \ - ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), TR_PREFS_TYPE ) ) - -#define TR_IS_PREFS_CLASS( class ) \ - ( G_TYPE_CHECK_CLASS_TYPE( (class), TR_PREFS_TYPE ) ) - -#define TR_PREFS_GET_CLASS( obj ) \ - ( G_TYPE_INSTANCE_GET_CLASS( (obj), TR_PREFS_TYPE, TrPrefsClass ) ) - -typedef struct _TrPrefs TrPrefs; -typedef struct _TrPrefsClass TrPrefsClass; - -/* treat the contents of this structure as private */ -struct _TrPrefs -{ - GtkDialog parent; - GtkTreeModel * combomodel; - GObject * core; - gulong sigid; - GtkWidget ** prefwids; - gboolean fileselhack; - gboolean disposed; -}; - -struct _TrPrefsClass -{ - GtkDialogClass parent; -}; - -GType -tr_prefs_get_type( void ); - -TrPrefs * -tr_prefs_new( GObject * core ); - -TrPrefs * -tr_prefs_new_with_parent( GObject * core, GtkWindow * parent ); - -/* please keep this in sync with defs in tr_prefs.c */ -enum -{ - PREF_ID_USEDOWNLIMIT = 0, - PREF_ID_DOWNLIMIT, - PREF_ID_USEUPLIMIT, - PREF_ID_UPLIMIT, - PREF_ID_ASKDIR, - PREF_ID_DIR, - PREF_ID_PORT, - PREF_ID_NAT, - PREF_ID_PEX, - PREF_ID_ICON, - PREF_ID_ASKQUIT, - PREF_ID_ADDSTD, - PREF_ID_ADDIPC, - PREF_ID_MSGLEVEL, - PREF_MAX_ID -}; - -const char * -tr_prefs_name( int id ); - -/* convenience macros and functions for reading pref by id */ -#define tr_prefs_get( id ) cf_getpref( tr_prefs_name( (id) ) ) - -gboolean -tr_prefs_get_int( int id, int * val ); - -gboolean -tr_prefs_get_bool( int id, gboolean * val ); - -int -tr_prefs_get_int_with_default( int id ); - -gboolean -tr_prefs_get_bool_with_default( int id ); +int tr_prefs_get_action( const char * key ); +void tr_prefs_set_action( const char * key, int action ); #endif diff --git a/gtk/tr_torrent.c b/gtk/tr_torrent.c index bc477e08d..c3263eeea 100644 --- a/gtk/tr_torrent.c +++ b/gtk/tr_torrent.c @@ -33,6 +33,7 @@ #include "tr_prefs.h" #include "tr_torrent.h" +#include "conf.h" #include "util.h" enum { @@ -283,8 +284,7 @@ tr_torrent_stop( TrTorrent * self ) static TrTorrent * maketorrent( tr_torrent * handle ) { - tr_torrentDisablePex( handle, - !tr_prefs_get_bool_with_default( PREF_ID_PEX ) ); + tr_torrentDisablePex( handle, !pref_flag_get( PREF_KEY_PEX ) ); return g_object_new( TR_TORRENT_TYPE, "torrent-handle", handle, diff --git a/gtk/util.c b/gtk/util.c index 18ff2613c..9f9e34589 100644 --- a/gtk/util.c +++ b/gtk/util.c @@ -35,6 +35,7 @@ #include "tr_prefs.h" #include "tr_torrent.h" +#include "conf.h" #include "util.h" #define BESTDECIMAL(d) (10.0 > (d) ? 2 : (100.0 > (d) ? 1 : 0)) @@ -51,28 +52,6 @@ tr_strcmp( const char * a, const char * b ) return 0; } -gboolean -strbool( const char * str ) -{ - if( !str ) - return FALSE; - - switch(str[0]) { - case 'y': - case 'Y': - case '1': - case 'j': - case 'e': - return TRUE; - default: - if(0 == g_ascii_strcasecmp("on", str)) - return TRUE; - break; - } - - return FALSE; -} - static const char *sizestrs[] = { N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), N_("PiB"), N_("EiB"), }; @@ -314,15 +293,15 @@ toractionname( enum tr_torrent_action action ) } } -const char * +char * getdownloaddir( void ) { static char * wd = NULL; - const char * dir = tr_prefs_get( PREF_ID_DIR ); - if (NULL == dir) { - if (NULL == wd) - wd = g_get_current_dir(); - dir = wd; + char * dir = pref_string_get( PREF_KEY_DIR_DEFAULT ); + if ( dir == NULL ) { + if( wd == NULL ) + wd = g_get_current_dir(); + dir = g_strdup( wd ); } return dir; } diff --git a/gtk/util.h b/gtk/util.h index 44f8b160e..aa80a97e4 100644 --- a/gtk/util.h +++ b/gtk/util.h @@ -44,11 +44,6 @@ enum tr_torrent_action { TR_TOR_LEAVE, TR_TOR_COPY, TR_TOR_MOVE }; /* used for a callback function with a data parameter */ typedef void (*callbackfunc_t)(void*); -/* try to interpret a string as a textual representation of a boolean */ -/* note that this isn't localized */ -gboolean -strbool(const char *str); - /* return a human-readable string for the size given in bytes. the string must be g_free()d */ char * @@ -106,7 +101,7 @@ const char * toractionname( enum tr_torrent_action action ); /* retrieve the global download directory */ -const char * +char * getdownloaddir( void ); #ifdef GTK_MAJOR_VERSION