Changeset 3206


Ignore:
Timestamp:
Sep 27, 2007, 8:57:58 PM (14 years ago)
Author:
charles
Message:

preferences code refresh in the gtk+ client

Location:
trunk/gtk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/conf.c

    r2392 r3206  
    3737#include <glib/gi18n.h>
    3838
     39#include <libtransmission/transmission.h>
     40#include <libtransmission/bencode.h>
     41
    3942#include "conf.h"
    4043#include "util.h"
     
    6669cf_writebenc(const char *file, const char *tmp, benc_val_t *data,
    6770             char **errstr);
    68 static gboolean
    69 writefile_traverse(gpointer key, gpointer value, gpointer data);
    7071static char *
    7172getstateval(benc_val_t *state, char *line);
     
    7374static char *gl_confdir = NULL;
    7475static char *gl_old_confdir = NULL;
    75 static GTree *gl_prefs = NULL;
    7676static char *gl_lockpath = NULL;
    7777static char *gl_old_lockpath = NULL;
     
    181181  char *path;
    182182  GIOChannel *io;
    183   GError *err;
     183  GError *err = NULL;
    184184  char *ret;
    185185
     
    223223}
    224224
    225 void
    226 cf_loadprefs(char **errstr) {
    227   char *data, *line, *eol, *sep, *key;
    228   gsize len;
    229   benc_val_t val;
    230   gboolean usedold;
    231   int ii;
    232 
    233   *errstr = NULL;
    234 
    235   if(NULL != gl_prefs)
    236     g_tree_destroy(gl_prefs);
    237 
    238   gl_prefs = g_tree_new_full((GCompareDataFunc)g_ascii_strcasecmp, NULL,
    239                           g_free, g_free);
    240 
    241   data = cf_readfile(FILE_PREFS, OLD_FILE_PREFS, &len, &usedold, errstr);
    242   if(NULL != *errstr) {
    243     g_assert(NULL == data);
    244     return;
    245   }
    246 
    247   if(NULL == data)
    248     return;
    249 
    250   memset(&val, 0,  sizeof(val));
    251   if(!usedold && !tr_bencLoad(data, len, &val, NULL)) {
    252     if(TYPE_DICT == val.type) {
    253       key = NULL;
    254       for(ii = 0; ii < val.val.l.count; ii++) {
    255         if(NULL == key) {
    256           g_assert(TYPE_STR == val.val.l.vals[ii].type);
    257           key = val.val.l.vals[ii].val.s.s;
    258         } else {
    259           if(TYPE_INT == val.val.l.vals[ii].type)
    260             g_tree_insert(gl_prefs, g_strdup(key),
    261                          g_strdup_printf("%"PRIu64, val.val.l.vals[ii].val.i));
    262           else if(TYPE_STR == val.val.l.vals[ii].type)
    263             g_tree_insert(gl_prefs, g_strdup(key),
    264                           g_strdup(val.val.l.vals[ii].val.s.s));
    265           key = NULL;
    266         }
    267       }
     225/**
     226***  Prefs Files
     227**/
     228
     229#define DEFAULT_GROUP "general"
     230
     231static char*
     232getPrefsFilename( void )
     233{
     234    return g_build_filename( tr_getPrefsDirectory(), "gtk", "prefs", NULL );
     235}
     236
     237static GKeyFile*
     238getPrefsKeyFile( void )
     239{
     240    static GKeyFile * myKeyFile = NULL;
     241
     242    if( myKeyFile == NULL )
     243    {
     244        char * filename = getPrefsFilename( );
     245        myKeyFile = g_key_file_new( );
     246        g_key_file_load_from_file( myKeyFile, filename, 0, NULL );
     247        g_free( filename );
    268248    }
    269249
    270   } else {
    271     /* XXX remove this in a release or two */
    272     for(line = data; NULL != (eol = strchr(line, PREF_SEP_LINE));
    273         line = eol + 1) {
    274       *eol = '\0';
    275       if(g_utf8_validate(line, -1, NULL) &&
    276          NULL != (sep = strchr(line, PREF_SEP_KEYVAL))) {
    277         *sep = '\0';
    278         g_tree_insert(gl_prefs, g_strcompress(line), g_strcompress(sep+1));
    279       }
     250    return myKeyFile;
     251}
     252
     253int
     254pref_int_get( const char * key )
     255{
     256    return g_key_file_get_integer( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL );
     257}
     258void
     259pref_int_set( const char * key, int value )
     260{
     261    g_key_file_set_integer( getPrefsKeyFile( ), DEFAULT_GROUP, key, value );
     262}
     263void
     264pref_int_set_default( const char * key, int value )
     265{
     266    if( !g_key_file_has_key( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ) )
     267        pref_int_set( key, value );
     268}
     269
     270gboolean
     271pref_flag_get ( const char * key )
     272{
     273    return g_key_file_get_boolean( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL );
     274}
     275void
     276pref_flag_set( const char * key, gboolean value )
     277{
     278    g_key_file_set_boolean( getPrefsKeyFile( ), DEFAULT_GROUP, key, value );
     279}
     280void
     281pref_flag_set_default( const char * key, gboolean value )
     282{
     283    if( !g_key_file_has_key( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ) )
     284        pref_flag_set( key, value );
     285}
     286
     287char*
     288pref_string_get( const char * key )
     289{
     290    return g_key_file_get_string( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL );
     291}
     292void
     293pref_string_set( const char * key, const char * value )
     294{
     295    g_key_file_set_string( getPrefsKeyFile( ), DEFAULT_GROUP, key, value );
     296}
     297void
     298pref_string_set_default( const char * key, const char * value )
     299{
     300    if( !g_key_file_has_key( getPrefsKeyFile( ), DEFAULT_GROUP, key, NULL ) )
     301        pref_string_set( key, value );
     302}
     303
     304void
     305pref_save(char **errstr)
     306{
     307    GError * err = NULL;
     308    gsize datalen;
     309    char * data;
     310    char * filename = getPrefsFilename( );
     311
     312    data = g_key_file_to_data( getPrefsKeyFile(), &datalen, &err );
     313    if( !err ) {
     314        GIOChannel * out = g_io_channel_new_file( filename, "w+", &err );
     315        g_io_channel_write_chars( out, data, datalen, NULL, &err );
     316        g_io_channel_unref( out );
    280317    }
    281     cf_saveprefs(errstr);
    282   }
    283 
    284   tr_bencFree(&val);
    285   g_free(data);
    286 }
     318
     319    if( errstr != NULL )
     320        *errstr = err ? g_strdup( err->message ) : NULL;
     321
     322    g_free( filename );
     323    g_free( data );
     324    g_clear_error( &err );
     325}
     326
     327/**
     328***
     329**/
    287330
    288331benc_val_t *
     
    338381}
    339382
    340 const char *
    341 cf_getpref(const char *name) {
    342   g_assert(NULL != gl_prefs);
    343 
    344   return g_tree_lookup(gl_prefs, name);
    345 }
    346 
    347 void
    348 cf_setpref(const char *name, const char *value) {
    349   g_assert(NULL != gl_prefs);
    350 
    351   g_tree_insert(gl_prefs, g_strdup(name), g_strdup(value));
    352 }
    353 
    354383static void
    355384cf_writebenc(const char *file, const char *tmp, benc_val_t *data,
     
    358387  char *pathtmp = g_build_filename(gl_confdir, tmp, NULL);
    359388  GIOChannel *io = NULL;
    360   GError *err;
     389  GError *err = NULL;
    361390  char *datastr;
    362391  int len;
     
    403432}
    404433
    405 void
    406 cf_saveprefs(char **errstr) {
    407   benc_val_t val;
    408   benc_val_t *ptr;
    409 
    410   *errstr = NULL;
    411 
    412   memset(&val, 0,  sizeof(val));
    413   val.type = TYPE_DICT;
    414   val.val.l.alloc = val.val.l.count = g_tree_nnodes(gl_prefs) * 2;
    415   val.val.l.vals = g_new0(benc_val_t, val.val.l.alloc);
    416 
    417   ptr = val.val.l.vals;
    418   g_tree_foreach(gl_prefs, writefile_traverse, &ptr);
    419   g_assert(ptr - val.val.l.vals == val.val.l.alloc);
    420 
    421   cf_writebenc(FILE_PREFS, FILE_PREFS_TMP, &val, errstr);
    422   tr_bencFree(&val);
    423 }
    424 
    425434static gboolean
    426 writefile_traverse(gpointer key, gpointer value, gpointer data) {
    427   benc_val_t **ptr = data;
    428   benc_val_t *bkey = *ptr;
    429   benc_val_t *bval = (*ptr) + 1;
    430 
    431   *ptr = (*ptr) + 2;
    432 
    433   bkey->type = TYPE_STR;
    434   bkey->val.s.s = g_strdup(key);
    435   bkey->val.s.i = strlen(key);
    436 
    437   bval->type = TYPE_STR;
    438   bval->val.s.s = g_strdup(value);
    439   bval->val.s.i = strlen(value);
     435strbool( const char * str )
     436{
     437  if( !str )
     438    return FALSE;
     439
     440  switch(str[0]) {
     441    case 'y': case 't': case 'Y': case '1': case 'j': case 'e':
     442      return TRUE;
     443    default:
     444      if(0 == g_ascii_strcasecmp("on", str))
     445        return TRUE;
     446      break;
     447  }
    440448
    441449  return FALSE;
    442450}
     451
    443452
    444453static char *
  • trunk/gtk/conf.h

    r2400 r3206  
    2323 *****************************************************************************/
    2424
     25/**
     26***
     27**/
     28
    2529#ifndef TG_CONF_H
    2630#define TG_CONF_H
    2731
    28 #include <libtransmission/transmission.h>
    29 #include <libtransmission/bencode.h>
     32int       pref_int_get            ( const char * key );
     33void      pref_int_set            ( const char * key, int value );
     34void      pref_int_set_default    ( const char * key, int default_value );
     35
     36gboolean  pref_flag_get            ( const char * key );
     37void      pref_flag_set            ( const char * key, gboolean value );
     38void      pref_flag_set_default    ( const char * key, gboolean default_value );
     39
     40char*     pref_string_get          ( const char * key );
     41void      pref_string_set          ( const char * key, const char * value );
     42void      pref_string_set_default  ( const char * key, const char * default_value );
     43
     44void      pref_save                ( char **errstr );
     45
     46/**
     47***
     48**/
     49
     50struct benc_val_s;
    3051
    3152gboolean
     
    3758void
    3859cf_loadprefs(char **errstr);
    39 const char *
    40 cf_getpref(const char *name);
    41 void
    42 cf_setpref(const char *name, const char *value);
    43 void
    44 cf_saveprefs(char **errstr);
    45 benc_val_t *
     60struct benc_val_s *
    4661cf_loadstate(char **errstr);
    4762void
    48 cf_savestate(benc_val_t *state, char **errstr);
     63cf_savestate(struct benc_val_s *state, char **errstr);
    4964void
    50 cf_freestate(benc_val_t *state);
     65cf_freestate(struct benc_val_s *state);
    5166
    5267#endif /* TG_CONF_H */
  • trunk/gtk/dialogs.c

    r3111 r3206  
    130130  GtkWidget *getdir = gtk_file_chooser_button_new(
    131131    _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
    132   const char * pref;
     132  char * pref;
    133133
    134134  data->widget = wind;
     
    149149
    150150  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
    151   pref = tr_prefs_get( PREF_ID_DIR );
    152   if( NULL != pref )
    153   {
     151  pref = pref_string_get( PREF_KEY_DIR_DEFAULT );
     152  if( pref != NULL ) {
    154153      gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( wind ), pref );
     154      g_free( pref );
    155155  }
    156156
     
    215215      dir = gtk_file_chooser_get_filename(data->altdir);
    216216    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
    217     action = toraddaction( tr_prefs_get( PREF_ID_ADDSTD ) );
     217    action = tr_prefs_get_action( PREF_KEY_ADDSTD );
     218
    218219    if( NULL == dir )
    219220    {
     
    269270              size_t size, enum tr_torrent_action act, gboolean paused )
    270271{
     272    char * path;
    271273    struct dirdata * stuff;
    272274    GtkWidget      * wind;
     
    296298    gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( wind ), TRUE );
    297299    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( wind ), FALSE );
    298     gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ),
    299                                    getdownloaddir() );
     300    path = getdownloaddir( );
     301    gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ), path );
     302    g_free( path );
    300303
    301304    stuff->widget = wind;
     
    373376quitresp( GtkWidget * widget, int response, gpointer data )
    374377{
    375     struct quitdata * stuff;
    376     gboolean doask;
    377 
    378     stuff = data;
    379 
    380     doask = !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(stuff->dontask) );
    381     tr_core_set_pref_bool( stuff->core, PREF_ID_ASKQUIT, doask );
     378    struct quitdata * stuff = data;
     379
     380    pref_flag_set( PREF_KEY_ASKQUIT,
     381                   !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(stuff->dontask) ) );
    382382
    383383    if( response == GTK_RESPONSE_ACCEPT )
     
    398398    GtkWidget * dontask;
    399399
    400     if( !tr_prefs_get_bool_with_default( PREF_ID_ASKQUIT ) )
     400    if( !pref_flag_get( PREF_KEY_ASKQUIT ) )
    401401    {
    402402        func( cbdata );
  • trunk/gtk/ipc.c

    r3111 r3206  
    591591    }
    592592
    593     action = toraddaction( tr_prefs_get( PREF_ID_ADDIPC ) );
     593    action = tr_prefs_get_action( PREF_KEY_ADDIPC );
    594594    for( ii = 0; ii < val->val.l.count; ii++ )
    595595    {
     
    638638    }
    639639
    640     action = toraddaction( tr_prefs_get( PREF_ID_ADDIPC ) );
     640    action = tr_prefs_get_action( PREF_KEY_ADDIPC );
    641641    paused = ( NULL == start || start->val.i ? FALSE : TRUE );
    642642    if( NULL != file )
     
    998998            break;
    999999        case IPC_MSG_GETDIR:
    1000             pref = tr_prefs_get( PREF_ID_ASKDIR );
    10011000            /* XXX sending back "" when we're prompting is kind of bogus */
    1002             pref = strbool( pref ) ? "" : getdownloaddir();
     1001            pref = pref_flag_get( PREF_KEY_DIR_ASK ) ? "" : getdownloaddir();
    10031002            buf = ipc_mkstr( con->ipc, &size, IPC_MSG_DIR, tag, pref );
    10041003            break;
    10051004        case IPC_MSG_GETDOWNLIMIT:
    1006             num = -1;
    1007             if( tr_prefs_get_bool_with_default( PREF_ID_USEDOWNLIMIT ) )
    1008             {
    1009                 num = tr_prefs_get_int_with_default( PREF_ID_DOWNLIMIT );
    1010             }
     1005            num = pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED )
     1006                ? pref_int_get( PREF_KEY_DL_LIMIT )
     1007                : -1;
    10111008            buf = ipc_mkint( con->ipc, &size, IPC_MSG_DOWNLIMIT, tag, num );
    10121009            break;
    10131010        case IPC_MSG_GETPEX:
    10141011            buf = ipc_mkint( con->ipc, &size, IPC_MSG_PEX, tag,
    1015                              tr_prefs_get_bool_with_default( PREF_ID_PEX ) );
     1012                             pref_flag_get( PREF_KEY_PEX ) );
    10161013            break;
    10171014        case IPC_MSG_GETPORT:
    10181015            buf = ipc_mkint( con->ipc, &size, IPC_MSG_PORT, tag,
    1019                              tr_prefs_get_int_with_default( PREF_ID_PORT ) );
     1016                             pref_flag_get( PREF_KEY_PORT ) );
    10201017            break;
    10211018        case IPC_MSG_GETUPLIMIT:
    1022             num = -1;
    1023             if( tr_prefs_get_bool_with_default( PREF_ID_USEUPLIMIT ) )
    1024             {
    1025                 num = tr_prefs_get_int_with_default( PREF_ID_UPLIMIT );
    1026             }
     1019            num = pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED )
     1020                ? pref_int_get( PREF_KEY_UL_LIMIT )
     1021                : -1;
    10271022            buf = ipc_mkint( con->ipc, &size, IPC_MSG_UPLIMIT, tag, num );
    10281023            break;
     
    10531048    {
    10541049        case IPC_MSG_AUTOMAP:
    1055             tr_core_set_pref_bool( srv->core, PREF_ID_NAT, val->val.i );
     1050            tr_core_set_pref_bool( srv->core, PREF_KEY_NAT, val->val.i );
    10561051            break;
    10571052        case IPC_MSG_AUTOSTART:
     
    10611056            if( 0 > val->val.i )
    10621057            {
    1063                 tr_core_set_pref_bool( srv->core, PREF_ID_USEDOWNLIMIT,
    1064                                        FALSE );
     1058                tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 0 );
    10651059            }
    10661060            else
    10671061            {
    1068                 tr_core_set_pref_int( srv->core, PREF_ID_DOWNLIMIT,
    1069                                       val->val.i );
    1070                 tr_core_set_pref_bool( srv->core, PREF_ID_USEDOWNLIMIT, TRUE );
     1062                tr_core_set_pref_int( srv->core, PREF_KEY_DL_LIMIT, val->val.i );
     1063                tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 1 );
    10711064            }
    10721065            break;
    10731066        case IPC_MSG_PEX:
    1074             tr_core_set_pref_bool( srv->core, PREF_ID_PEX, val->val.i );
     1067            tr_core_set_pref_bool( srv->core, PREF_KEY_PEX, val->val.i );
    10751068            break;
    10761069        case IPC_MSG_PORT:
    1077             tr_core_set_pref_int( srv->core, PREF_ID_PORT, val->val.i );
     1070            tr_core_set_pref_int( srv->core, PREF_KEY_PORT, val->val.i );
    10781071            break;
    10791072        case IPC_MSG_UPLIMIT:
    10801073            if( 0 > val->val.i )
    10811074            {
    1082                 tr_core_set_pref_bool( srv->core, PREF_ID_USEUPLIMIT,
    1083                                        FALSE );
     1075                tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 0 );
    10841076            }
    10851077            else
    10861078            {
    1087                 tr_core_set_pref_int( srv->core, PREF_ID_UPLIMIT,
    1088                                       val->val.i );
    1089                 tr_core_set_pref_bool( srv->core, PREF_ID_USEUPLIMIT, TRUE );
     1079                tr_core_set_pref_int( srv->core, PREF_KEY_UL_LIMIT, val->val.i );
     1080                tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 1 );
    10901081            }
    10911082            break;
     
    11111102    {
    11121103        case IPC_MSG_DIR:
    1113             tr_core_set_pref( srv->core, PREF_ID_DIR, val->val.s.s );
     1104            tr_core_set_pref( srv->core, PREF_KEY_DIR_DEFAULT, val->val.s.s );
    11141105            break;
    11151106        default:
  • trunk/gtk/main.c

    r3153 r3206  
    106106    GtkWidget    * icon;
    107107    GtkWidget    * msgwin;
    108     TrPrefs      * prefs;
     108    GtkWidget    * prefs;
    109109    guint          timer;
    110110    gboolean       closing;
     
    157157readinitialprefs( struct cbdata * cbdata );
    158158static void
    159 prefschanged( TrCore * core, int id, gpointer data );
     159prefschanged( TrCore * core, const char * key, gpointer data );
    160160static void
    161161setpex( tr_torrent * tor, void * arg );
     
    245245
    246246        /* try to load prefs and saved state */
    247         cf_loadprefs( &err );
    248         if( NULL != err )
    249         {
    250             errmsg( mainwind, "%s", err );
    251             g_free( err );
    252         }
     247        tr_prefs_init_global( );
    253248        state = cf_loadstate( &err );
    254249        if( NULL != err )
     
    429424    if( NULL != args )
    430425    {
    431         action = toraddaction( tr_prefs_get( PREF_ID_ADDIPC ) );
     426        action = tr_prefs_get_action( PREF_KEY_ADDIPC );
    432427        tr_core_add_list( cbdata->core, args, action, paused );
    433428    }
     
    660655    if( NULL != paths )
    661656    {
    662         action = toraddaction( tr_prefs_get( PREF_ID_ADDSTD ) );
     657        action = tr_prefs_get_action( PREF_KEY_ADDSTD );
    663658        tr_core_add_list( data->core, paths, action, FALSE );
    664659        tr_core_torrents_added( data->core );
     
    743738readinitialprefs( struct cbdata * cbdata )
    744739{
    745     int prefs[] =
    746     {
    747         PREF_ID_PORT,
    748         PREF_ID_DOWNLIMIT,
    749         PREF_ID_USEDOWNLIMIT,
    750         PREF_ID_UPLIMIT,
    751         PREF_ID_USEUPLIMIT,
    752         PREF_ID_NAT,
    753         PREF_ID_ICON,
    754         PREF_ID_PEX,
     740    size_t i;
     741    const char * keys[] =
     742    {
     743        PREF_KEY_PORT,
     744        PREF_KEY_DL_LIMIT_ENABLED,
     745        PREF_KEY_DL_LIMIT,
     746        PREF_KEY_UL_LIMIT_ENABLED,
     747        PREF_KEY_UL_LIMIT,
     748        PREF_KEY_NAT,
     749        PREF_KEY_PEX,
     750        PREF_KEY_SYSTRAY
    755751    };
    756     int ii;
    757 
    758     for( ii = 0; ALEN( prefs ) > ii; ii++ )
    759     {
    760         prefschanged( NULL, prefs[ii], cbdata );
    761     }
    762 }
    763 
    764 static void
    765 prefschanged( TrCore * core SHUTUP, int id, gpointer data )
     752
     753    for( i=0; i<G_N_ELEMENTS(keys); ++i )
     754        prefschanged( NULL, keys[i], cbdata );
     755}
     756
     757static void
     758prefschanged( TrCore * core UNUSED, const char * key, gpointer data )
    766759{
    767760    struct cbdata * cbdata = data;
    768761    tr_handle     * tr     = tr_core_handle( cbdata->core );
    769     gboolean        boolval;
    770 
    771     switch( id )
    772     {
    773         case PREF_ID_PORT:
    774             tr_setBindPort( tr, tr_prefs_get_int_with_default( id ) );
    775             break;
    776 
    777         case PREF_ID_USEDOWNLIMIT:
    778             tr_setUseGlobalSpeedLimit( tr, TR_DOWN,
    779                 tr_prefs_get_bool_with_default( PREF_ID_USEDOWNLIMIT ) );
    780             break;
    781 
    782         case PREF_ID_DOWNLIMIT:
    783             tr_setGlobalSpeedLimit( tr, TR_DOWN,
    784                 tr_prefs_get_int_with_default( PREF_ID_DOWNLIMIT ) );
    785             break;
    786 
    787         case PREF_ID_USEUPLIMIT:
    788             tr_setUseGlobalSpeedLimit( tr, TR_UP,
    789                 tr_prefs_get_bool_with_default( PREF_ID_USEUPLIMIT ) );
    790             break;
    791 
    792         case PREF_ID_UPLIMIT:
    793             tr_setGlobalSpeedLimit( tr, TR_UP,
    794                 tr_prefs_get_int_with_default( PREF_ID_UPLIMIT ) );
    795             break;
    796 
    797         case PREF_ID_NAT:
    798             tr_natTraversalEnable( tr, tr_prefs_get_bool_with_default( id ) );
    799             break;
    800 
    801         case PREF_ID_ICON:
    802             if( tr_prefs_get_bool_with_default( id ) )
    803             {
    804                 makeicon( cbdata );
    805             }
    806             else if( NULL != cbdata->icon )
    807             {
    808 g_message ("foo");
    809                 g_object_unref( cbdata->icon );
    810                 cbdata->icon = NULL;
    811             }
    812             break;
    813 
    814         case PREF_ID_PEX:
    815             boolval = tr_prefs_get_bool_with_default( id );
    816             tr_torrentIterate( tr, setpex, &boolval );
    817             break;
    818 
    819         case PREF_ID_DIR:
    820         case PREF_ID_ASKDIR:
    821         case PREF_ID_ADDSTD:
    822         case PREF_ID_ADDIPC:
    823         case PREF_ID_MSGLEVEL:
    824         case PREF_MAX_ID:
    825             break;
     762
     763    if( !strcmp( key, PREF_KEY_PORT ) )
     764    {
     765        const int port = pref_int_get( key );
     766        tr_setBindPort( tr, port );
     767    }
     768    else if( !strcmp( key, PREF_KEY_DL_LIMIT_ENABLED ) )
     769    {
     770        const gboolean b = pref_flag_get( key );
     771        tr_setUseGlobalSpeedLimit( tr, TR_DOWN, b );
     772    }
     773    else if( !strcmp( key, PREF_KEY_DL_LIMIT ) )
     774    {
     775        const int limit = pref_int_get( key );
     776        tr_setGlobalSpeedLimit( tr, TR_DOWN, limit );
     777    }
     778    else if( !strcmp( key, PREF_KEY_UL_LIMIT_ENABLED ) )
     779    {
     780        const gboolean b = pref_flag_get( key );
     781        tr_setUseGlobalSpeedLimit( tr, TR_UP, b );
     782    }
     783    else if( !strcmp( key, PREF_KEY_UL_LIMIT ) )
     784    {
     785        const int limit = pref_int_get( key );
     786        tr_setGlobalSpeedLimit( tr, TR_UP, limit );
     787    }
     788    else if( !strcmp( key, PREF_KEY_NAT ) )
     789    {
     790        const gboolean enabled = pref_flag_get( key );
     791        tr_natTraversalEnable( tr, enabled );
     792    }
     793    else if( !strcmp( key, PREF_KEY_SYSTRAY ) )
     794    {
     795        if( pref_flag_get( key ) ) {
     796            makeicon( cbdata );
     797        } else if( cbdata->icon ) {
     798            g_object_unref( cbdata->icon );
     799            cbdata->icon = NULL;
     800        }
     801    }
     802    else if( !strcmp( key, PREF_KEY_PEX ) )
     803    {
     804        gboolean enabled = pref_flag_get( key );
     805        tr_torrentIterate( tr, setpex, &enabled );
    826806    }
    827807}
     
    10651045        if( NULL == data->prefs )
    10661046        {
    1067             data->prefs = tr_prefs_new_with_parent( G_OBJECT( data->core ),
    1068                                                     data->wind );
     1047            data->prefs = tr_prefs_dialog_new( G_OBJECT(data->core), data->wind );
    10691048            g_signal_connect( data->prefs, "destroy",
    10701049                             G_CALLBACK( gtk_widget_destroyed ), &data->prefs );
  • trunk/gtk/msgwin.c

    r3126 r3206  
    142142        gtk_tree_model_get( m, &iter, 1, &id, -1 );
    143143        tr_setMessageLevel( id );
    144         tr_core_set_pref_int( core, PREF_ID_MSGLEVEL, id );
     144        tr_core_set_pref_int( core, PREF_KEY_MSGLEVEL, id );
    145145        msgwin_update( );
    146146    }
     
    260260  store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
    261261
    262   curlevel = TR_MSG_INF;
    263   tr_prefs_get_int( PREF_ID_MSGLEVEL, &curlevel );
     262  curlevel = pref_int_get( PREF_KEY_MSGLEVEL );
    264263  for( i=ii=0; i<G_N_ELEMENTS(trLevels); ++i ) {
    265264      GtkTreeIter iter;
     
    310309msgwin_loadpref( void )
    311310{
    312     int level = TR_MSG_INF;
    313311    textbuf = debug_window_text_buffer_new ( );
    314     tr_prefs_get_int( PREF_ID_MSGLEVEL, &level );
    315     tr_setMessageLevel( level );
     312    tr_setMessageLevel( pref_int_get( PREF_KEY_MSGLEVEL ) );
    316313    tr_setMessageQueuing( TRUE );
    317314}
  • trunk/gtk/tr_core.c

    r3178 r3206  
    119119                                        G_TYPE_FROM_CLASS( g_class ),
    120120                                        G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    121                                         g_cclosure_marshal_VOID__INT,
    122                                         G_TYPE_NONE, 1, G_TYPE_INT );
     121                                        g_cclosure_marshal_VOID__STRING,
     122                                        G_TYPE_NONE, 1, G_TYPE_STRING );
    123123}
    124124
     
    252252    }
    253253    self->disposed = TRUE;
     254
     255    pref_save( NULL );
    254256
    255257#ifdef REFDBG
     
    409411    int count = 0;
    410412    tr_torrent ** torrents;
    411     const char * destination;
    412 
    413     TR_IS_CORE( self );
    414 
    415     destination = getdownloaddir( );
     413    char * path;
     414
     415    TR_IS_CORE( self );
     416
     417    path = getdownloaddir( );
    416418
    417419    flags = 0;
     
    419421         flags |= TR_FLAG_PAUSED;
    420422
    421     torrents = tr_loadTorrents ( self->handle, destination, flags, &count );
     423    torrents = tr_loadTorrents ( self->handle, path, flags, &count );
    422424    for( i=0; i<count; ++i )
    423425        tr_core_insert( self, tr_torrent_new_preexisting( torrents[i] ) );
    424426    tr_free( torrents );
    425427
     428    g_free( path );
    426429    return count;
    427430}
     
    471474                  gboolean paused )
    472475{
    473     const char  * pref = tr_prefs_get( PREF_ID_ASKDIR );
    474     TrCoreClass * class;
    475     int           count;
    476 
    477     TR_IS_CORE( self );
    478 
    479     if( strbool( pref ) )
    480     {
    481         class = g_type_class_peek( TR_CORE_TYPE );
     476    char * dir;
     477    int count;
     478
     479    TR_IS_CORE( self );
     480
     481    if( pref_flag_get( PREF_KEY_DIR_ASK ) )
     482    {
     483        TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE );
    482484        g_signal_emit( self, class->promptsig, 0, paths, act, paused );
    483485        return 0;
    484486    }
    485487
    486     pref = getdownloaddir();
     488    dir = getdownloaddir();
    487489    count = 0;
    488490    for( ; paths; paths=paths->next )
    489         if( tr_core_add_dir( self, paths->data, pref, act, paused ) )
     491        if( tr_core_add_dir( self, paths->data, dir, act, paused ) )
    490492            count++;
    491493
     494    g_free( dir );
    492495    return count;
    493496}
     
    496499tr_core_add_data( TrCore * self, uint8_t * data, size_t size, gboolean paused )
    497500{
    498     const char  * pref = tr_prefs_get( PREF_ID_ASKDIR );
    499 
    500     TR_IS_CORE( self );
    501 
    502     if( strbool( pref ) )
     501    gboolean ret;
     502    char * path;
     503    TR_IS_CORE( self );
     504
     505    if( pref_flag_get( PREF_KEY_DIR_ASK ) )
    503506    {
    504507        TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE );
     
    507510    }
    508511
    509     return tr_core_add_data_dir( self, data, size, getdownloaddir(), paused );
     512    path = getdownloaddir( );
     513    ret = tr_core_add_data_dir( self, data, size, path, paused );
     514    g_free( path );
     515    return ret;
    510516}
    511517
     
    638644}
    639645
    640 void
    641 tr_core_set_pref( TrCore * self, int id, const char * val )
    642 {
    643     const char  * name, * old;
    644     char        * errstr;
    645     TrCoreClass * class;
    646 
    647     TR_IS_CORE( self );
    648 
    649     /* don't change anything if the new value is the same as the old one */
    650     name = tr_prefs_name( id );
    651     old = cf_getpref( name );
    652     if( !tr_strcmp( old, val ) )
    653         return;
    654 
    655     cf_setpref( name, val );
    656 
    657     /* write prefs to disk */
    658     cf_saveprefs( &errstr );
    659     if( NULL != errstr )
    660     {
    661         tr_core_errsig( self, TR_CORE_ERR_SAVE_STATE, errstr );
    662         g_free( errstr );
    663     }
    664 
    665     /* signal a pref change */
    666     class = g_type_class_peek( TR_CORE_TYPE );
    667     g_signal_emit( self, class->prefsig, 0, id );
    668 }
    669 
    670 void
    671 tr_core_set_pref_bool( TrCore * self, int id, gboolean val )
    672 {
    673     tr_core_set_pref( self, id, ( val ? "yes" : "no" ) );
    674 }
    675 
    676 void
    677 tr_core_set_pref_int( TrCore * self, int id, int val )
    678 {
    679     char buf[32];
    680 
    681     g_snprintf( buf, sizeof buf, "%i", val );
    682 
    683     tr_core_set_pref( self, id, buf );
    684 }
     646/**
     647***  Prefs
     648**/
     649
     650static void
     651commitPrefsChange( TrCore * self, const char * key )
     652{
     653    TrCoreClass * class = g_type_class_peek( TR_CORE_TYPE );
     654    pref_save( NULL );
     655    g_signal_emit( self, class->prefsig, 0, key );
     656}
     657
     658void
     659tr_core_set_pref( TrCore * self, const char * key, const char * newval )
     660{
     661    char * oldval = pref_string_get( key );
     662    if( tr_strcmp( oldval, newval ) )
     663    {
     664        pref_string_set( key, newval );
     665        commitPrefsChange( self, key );
     666    }
     667    g_free( oldval );
     668}
     669
     670void
     671tr_core_set_pref_bool( TrCore * self, const char * key, gboolean newval )
     672{
     673    const gboolean oldval = pref_flag_get( key );
     674    if( oldval != newval )
     675    {
     676        pref_flag_set( key, newval );
     677        commitPrefsChange( self, key );
     678    }
     679}
     680
     681void
     682tr_core_set_pref_int( TrCore * self, const char * key, int newval )
     683{
     684    const int oldval = pref_int_get( key );
     685    if( oldval != newval )
     686    {
     687        pref_int_set( key, newval );
     688        commitPrefsChange( self, key );
     689    }
     690}
  • trunk/gtk/tr_core.h

    r3111 r3206  
    173173   "prefs-changed" signal */
    174174void
    175 tr_core_set_pref( TrCore * self, int id, const char * val );
     175tr_core_set_pref( TrCore * self, const char * key, const char * val );
    176176
    177177/* Set a boolean preference value, save the prefs file, and emit the
    178178   "prefs-changed" signal */
    179179void
    180 tr_core_set_pref_bool( TrCore * self, int id, gboolean val );
     180tr_core_set_pref_bool( TrCore * self, const char * key, gboolean val );
    181181
    182182/* Set an integer preference value, save the prefs file, and emit the
    183183   "prefs-changed" signal */
    184184void
    185 tr_core_set_pref_int( TrCore * self, int id, int val );
     185tr_core_set_pref_int( TrCore * self, const char * key, int val );
    186186
    187187/* column names for the model used to store torrent information */
  • trunk/gtk/tr_prefs.c

    r2400 r3206  
    1 /******************************************************************************
    2  * $Id$
     1/*
     2 * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
    33 *
    4  * Copyright (c) 2005-2007 Transmission authors and contributors
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the "Software"),
    8  * to deal in the Software without restriction, including without limitation
    9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    10  * and/or sell copies of the Software, and to permit persons to whom the
    11  * Software is furnished to do so, subject to the following conditions:
    12  *
    13  * The above copyright notice and this permission notice shall be included in
    14  * all copies or substantial portions of the Software.
    15  *
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    22  * DEALINGS IN THE SOFTWARE.
    23  *****************************************************************************/
    24 
    25 #include <errno.h>
    26 #include <stdlib.h>
    27 #include <string.h>
    28 
     4 * This file is licensed by the GPL version 2.  Works owned by the
     5 * Transmission project are granted a special exemption to clause 2(b)
     6 * so that the bulk of its code can remain under the MIT license.
     7 * This exemption does not extend to derived works not owned by
     8 * the Transmission project.
     9 *
     10 * $Id:$
     11 */
     12
     13#include <glib/gi18n.h>
    2914#include <gtk/gtk.h>
    30 #include <glib/gi18n.h>
    31 
    3215#include <libtransmission/transmission.h>
    33 
    3416#include "conf.h"
    35 #include "tr_icon.h"
     17#include "hig.h"
    3618#include "tr_core.h"
    3719#include "tr_prefs.h"
    38 #include "tr_torrent.h"
    3920#include "util.h"
    4021
    41 /* used for g_object_set/get_data */
    42 #define PREF_CHECK_LINK         "tr-prefs-check-link-thingy"
    43 #define PREF_SPIN_LAST          "tr-prefs-spinbox-last-val"
    44 
    45 /* convenience macros for saving pref id on a widget */
    46 #define SETPREFID( wid, id )                                                  \
    47     ( g_object_set_data( G_OBJECT( (wid) ), "tr-prefs-id",                    \
    48                          GINT_TO_POINTER( (id) + 1 ) ) )
    49 #define GETPREFID( wid, id )                                                  \
    50     do                                                                        \
    51     {                                                                         \
    52         (id) = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( (wid) ),         \
    53                                                    "tr-prefs-id" ) );         \
    54         g_assert( 0 < (id) );                                                 \
    55         (id)--;                                                               \
    56     }                                                                         \
    57     while( 0 )
    58 
    59 enum
    60 {
    61     PROP_PARENT = 1,
    62     PROP_CORE
    63 };
    64 
    65 #define PTYPE( id )                                                           \
    66     ( G_TYPE_NONE == defs[(id)]._type ?                                       \
    67       defs[(id)].typefunc() : defs[(id)]._type )
    68 
    69 /* please keep this in sync with the enum in tr_prefs.c */
    70 /* don't forget defs_int, defs_bool, and defs_file too */
    71 static struct
    72 {
    73     char       * name;
    74     GType        _type;         /* don't access this directly, use PTYPE() */
    75     enum { PR_ENABLED, PR_DISABLED, PR_SKIP } status;
    76     GType (*typefunc)(void);
    77     const char * label;
    78     const char * tip;
    79 }
    80 defs[] =
    81 {
    82     /* PREF_ID_USEDOWNLIMIT */
    83     { "use-download-limit",     G_TYPE_BOOLEAN, PR_ENABLED,  NULL,
    84       N_("_Limit download speed"),
    85       N_("Restrict the download rate") },
    86 
    87     /* PREF_ID_DOWNLIMIT */
    88     { "download-limit",         G_TYPE_INT,     PR_ENABLED,  NULL,
    89       N_("Maximum _download speed:"),
    90       N_("Speed in KiB/sec for restricted download rate") },
    91 
    92     /* PREF_ID_USEUPLIMIT */
    93     { "use-upload-limit",       G_TYPE_BOOLEAN, PR_ENABLED,  NULL,
    94       N_("Li_mit upload speed"),
    95       N_("Restrict the upload rate") },
    96 
    97     /* PREF_ID_UPLIMIT */
    98     { "upload-limit",           G_TYPE_INT,     PR_ENABLED,  NULL,
    99       N_("Maximum _upload speed:"),
    100       N_("Speed in KiB/sec for restricted upload rate") },
    101 
    102     /* PREF_ID_ASKDIR */
    103     { "ask-download-directory", G_TYPE_BOOLEAN, PR_ENABLED,  NULL,
    104       N_("Al_ways prompt for download directory"),
    105       N_("When adding a torrent, always prompt for a directory to download data files into") },
    106 
    107     /* PREF_ID_DIR */
    108     { "download-directory",     G_TYPE_NONE,   PR_ENABLED,
    109       gtk_file_chooser_get_type,
    110       N_("Download di_rectory:"),
    111       N_("Destination directory for downloaded data files") },
    112 
    113     /* PREF_ID_PORT */
    114     { "listening-port",         G_TYPE_INT,     PR_ENABLED,  NULL,
    115       N_("Listening _port:"),
    116       N_("TCP port number to listen for peer connections") },
    117 
    118     /* PREF_ID_NAT */
    119     { "use-nat-traversal",      G_TYPE_BOOLEAN, PR_ENABLED,  NULL,
    120       N_("Au_tomatic port mapping via NAT-PMP or UPnP"),
    121       N_("Attempt to bypass NAT or firewall to allow incoming peer connections") },
    122 
    123     /* PREF_ID_PEX */
    124     { "use-peer-exchange",      G_TYPE_BOOLEAN, PR_ENABLED,  NULL,
    125       N_("Use peer _exchange if possible"),
    126       N_("Perform Azureus or \xc2\xb5Torrent compatible peer exchange with any peers which support it") },
    127 
    128     /* PREF_ID_ICON */
    129     { "use-tray-icon",          G_TYPE_BOOLEAN,
    130       ( status_icon_supported() ? PR_ENABLED : PR_DISABLED ),    NULL,
    131       N_("Display an _icon in the system tray"),
    132       N_("Use a system tray / dock / notification area icon") },
    133 
    134     /* PREF_ID_ASKQUIT */
    135     { "ask-quit",               G_TYPE_BOOLEAN, PR_ENABLED,  NULL,
    136       N_("Confirm _quit"),
    137       N_("Prompt for confirmation when quitting") },
    138 
    139     /* PREF_ID_ADDSTD */
    140     { "add-behavior-standard",  G_TYPE_NONE,    PR_ENABLED,
    141       gtk_combo_box_get_type,
    142       N_("For torrents added _normally:"),
    143       N_("Torrent files added via the toolbar, popup menu, and drag-and-drop") },
    144 
    145     /* PREF_ID_ADDIPC */
    146     { "add-behavior-ipc",       G_TYPE_NONE,    PR_ENABLED,
    147       gtk_combo_box_get_type,
    148       N_("For torrents added e_xternally\n(via the command-line):"),
    149       N_("For torrents added via the command-line only") },
    150 
    151     /* PREF_ID_MSGLEVEL */
    152     { "message-level",          G_TYPE_INT,     PR_SKIP, NULL, NULL, NULL },
    153 };
    154 
    155 static struct
    156 {
    157     long min;
    158     long max;
    159     long def;
    160 }
    161 defs_int[] =
    162 {
    163     { 0, 0, 0 },
    164     /* PREF_ID_DOWNLIMIT */
    165     { 0, G_MAXLONG, 100 },
    166     { 0, 0, 0 },
    167     /* PREF_ID_UPLIMIT */
    168     { 0, G_MAXLONG, 20 },
    169     { 0, 0, 0 }, { 0, 0, 0 },
    170     /* PREF_ID_PORT */
    171     { 1, 0xffff,    TR_DEFAULT_PORT },
    172 };
    173 
    174 static struct
    175 {
    176     gboolean def;
    177     int      link;
    178     gboolean enables;
    179 }
    180 defs_bool[] =
    181 {
    182     /* PREF_ID_USEDOWNLIMIT */
    183     { FALSE, PREF_ID_DOWNLIMIT, TRUE },
    184     { FALSE, -1, FALSE },
    185     /* PREF_ID_USEUPLIMIT */
    186     { FALSE, PREF_ID_UPLIMIT,   TRUE },
    187     { FALSE, -1, FALSE },
    188     /* PREF_ID_ASKDIR */
    189     { FALSE, PREF_ID_DIR,       FALSE },
    190     { FALSE, -1, FALSE }, { FALSE, -1, FALSE },
    191     /* PREF_ID_NAT */
    192     { TRUE,  -1,                FALSE },
    193     /* PREF_ID_PEX */
    194     { TRUE,  -1,                FALSE },
    195     /* PREF_ID_ICON */
    196     { TRUE,  -1,                FALSE },
    197     /* PREF_ID_ASKQUIT */
    198     { TRUE,  -1,                FALSE },
    199 };
    200 
    201 static struct
    202 {
    203     const char         * title;
    204     GtkFileChooserAction act;
    205     const char * (*getdef)(void);
    206 }
    207 defs_file[] =
    208 {
    209     { NULL, 0, NULL }, { NULL, 0, NULL }, { NULL, 0, NULL },
    210     { NULL, 0, NULL }, { NULL, 0, NULL },
    211     /* PREF_ID_DIR */
    212     { N_("Choose a download directory"),
    213       GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
    214       getdownloaddir },
    215 };
    216 
    217 struct checkctl
    218 {
    219     GtkToggleButton * check;
    220     GtkWidget       * wids[2];
    221     gboolean          enables;
    222 };
    223 
    224 static void
    225 tr_prefs_init( GTypeInstance * instance, gpointer g_class );
    226 static void
    227 tr_prefs_set_property( GObject * object, guint property_id,
    228                       const GValue * value, GParamSpec * pspec );
    229 static void
    230 tr_prefs_get_property( GObject * object, guint property_id,
    231                       GValue * value, GParamSpec * pspec);
    232 static void
    233 tr_prefs_class_init( gpointer g_class, gpointer g_class_data );
    234 static void
    235 tr_prefs_dispose( GObject * obj );
    236 static void
    237 gotresp( GtkWidget * widget, int resp, gpointer data );
    238 static int
    239 countprefs( void );
    240 static void
    241 makelinks( struct checkctl ** links );
    242 static void
    243 filllinks( int id, GtkWidget * wid1, GtkWidget * wid2,
    244            struct checkctl ** links );
    245 static void
    246 pokelink( struct checkctl * link );
    247 static void
    248 addwidget( TrPrefs * self, int id, GtkTable * table, int off,
    249            GtkTooltips * tips, struct checkctl ** links, GtkWidget ** wids );
    250 static GtkWidget *
    251 tipbox( GtkWidget * widget, GtkTooltips * tips, const char * tip );
    252 static void
    253 addwid_bool( TrPrefs * self, int id, GtkTooltips * tips,
    254              GtkWidget ** wid1, struct checkctl ** links, GtkWidget ** wids );
    255 static void
    256 checkclick( GtkWidget * widget, gpointer data );
    257 static void
    258 addwid_int( TrPrefs * self, int id, GtkTooltips * tips,
    259             GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids );
    260 static gboolean
    261 spinfocus( GtkWidget * widget, GdkEventFocus *event, gpointer data );
    262 static void
    263 spindie( GtkWidget * widget, gpointer data );
    264 static void
    265 addwid_file( TrPrefs * self, int id, GtkTooltips * tips,
    266              GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids );
    267 static void
    268 filechosen( GtkWidget * widget, gpointer data );
    269 static GtkTreeModel *
    270 makecombomodel( void );
    271 static void
    272 addwid_combo( TrPrefs * self, int id, GtkTooltips * tips,
    273               GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids );
    274 static void
    275 setcombosel( GtkTreeModel * model, GtkComboBox * combo, int id );
    276 static void
    277 combochosen( GtkWidget * widget, gpointer data );
    278 static void
    279 prefschanged( TrCore * core, int id, gpointer data );
    280 
    281 GType
    282 tr_prefs_get_type( void )
    283 {
    284     static GType type = 0;
    285 
    286     if( 0 == type )
     22/**
     23 * This is where we initialize the preferences file with the default values.
     24 * If you add a new preferences key, you /must/ add a default value here.
     25 */
     26void
     27tr_prefs_init_global( void )
     28{
     29    pref_flag_set_default   ( PREF_KEY_DL_LIMIT_ENABLED, FALSE );
     30    pref_int_set_default    ( PREF_KEY_DL_LIMIT, 100 );
     31    pref_flag_set_default   ( PREF_KEY_UL_LIMIT_ENABLED, FALSE );
     32    pref_int_set_default    ( PREF_KEY_UL_LIMIT, 50 );
     33
     34    pref_flag_set_default   ( PREF_KEY_DIR_ASK, FALSE );
     35    pref_string_set_default ( PREF_KEY_DIR_DEFAULT, g_get_home_dir() );
     36
     37    pref_int_set_default    ( PREF_KEY_PORT, TR_DEFAULT_PORT );
     38
     39    pref_flag_set_default   ( PREF_KEY_NAT, TRUE );
     40    pref_flag_set_default   ( PREF_KEY_PEX, TRUE );
     41    pref_flag_set_default   ( PREF_KEY_SYSTRAY, TRUE );
     42    pref_flag_set_default   ( PREF_KEY_ASKQUIT, TRUE );
     43
     44    pref_string_set_default ( PREF_KEY_ADDSTD, toractionname(TR_TOR_COPY) );
     45    pref_string_set_default ( PREF_KEY_ADDIPC, toractionname(TR_TOR_COPY) );
     46
     47    pref_int_set_default    ( PREF_KEY_MSGLEVEL, TR_MSG_INF );
     48
     49    pref_save( NULL );
     50}
     51
     52/**
     53***
     54**/
     55
     56int
     57tr_prefs_get_action( const char * key )
     58{
     59    char * val = pref_string_get( key );
     60    const int ret = toraddaction( val );
     61    g_free( val );
     62    return ret;
     63}
     64
     65void
     66tr_prefs_set_action( const char * key, int action )
     67{
     68    pref_string_set( key, toractionname(action) );
     69}
     70
     71/**
     72***
     73**/
     74
     75#define PREFS_KEY "prefs-key"
     76
     77static void
     78response_cb( GtkDialog * dialog, int response UNUSED, gpointer unused UNUSED )
     79{
     80    gtk_widget_destroy( GTK_WIDGET(dialog) );
     81}
     82
     83static void
     84toggled_cb( GtkToggleButton * w, gpointer core )
     85{
     86    const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY );
     87    const gboolean flag = gtk_toggle_button_get_active( w );
     88    tr_core_set_pref_bool( TR_CORE(core), key, flag );
     89}
     90
     91static GtkWidget*
     92new_check_button( const char * mnemonic, const char * key, gpointer core )
     93{
     94    GtkWidget * w = gtk_check_button_new_with_mnemonic( mnemonic );
     95    g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free );
     96    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w), pref_flag_get(key) );
     97    g_signal_connect( w, "toggled", G_CALLBACK(toggled_cb), core );
     98    return w;
     99}
     100
     101static void
     102spun_cb( GtkSpinButton * w, gpointer core )
     103{
     104    const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY );
     105    const int value = gtk_spin_button_get_value_as_int( w );
     106    tr_core_set_pref_int( TR_CORE(core), key, value );
     107}
     108
     109static GtkWidget*
     110new_spin_button( const char * key, gpointer core, int low, int high )
     111{
     112    GtkWidget * w = gtk_spin_button_new_with_range( low, high, 1 );
     113    g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free );
     114    gtk_spin_button_set_digits( GTK_SPIN_BUTTON(w), 0 );
     115    gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), pref_int_get(key) );
     116    g_signal_connect( w, "value-changed", G_CALLBACK(spun_cb), core );
     117    return w;
     118}
     119
     120static void
     121chosen_cb( GtkFileChooser * w, gpointer core )
     122{
     123    const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY );
     124    char * value = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(w) );
     125    tr_core_set_pref( TR_CORE(core), key, value );
     126    g_free( value );
     127}
     128
     129static GtkWidget*
     130new_path_chooser_button( const char * key, gpointer core )
     131{
     132    GtkWidget * w = gtk_file_chooser_button_new( "asdf", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
     133    char * path = pref_string_get( key );
     134    g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free );
     135    g_signal_connect( w, "selection-changed", G_CALLBACK(chosen_cb), core );
     136    gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(w), path );
     137    return w;
     138}
     139
     140static void
     141action_cb( GtkComboBox * w, gpointer core )
     142{
     143    const char * key = g_object_get_data( G_OBJECT(w), PREFS_KEY );
     144    GtkTreeIter iter;
     145    if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX(w), &iter ) )
    287146    {
    288         static const GTypeInfo info =
    289         {
    290             sizeof( TrPrefsClass ),
    291             NULL,                       /* base_init */
    292             NULL,                       /* base_finalize */
    293             tr_prefs_class_init,        /* class_init */
    294             NULL,                       /* class_finalize */
    295             NULL,                       /* class_data */
    296             sizeof( TrPrefs ),
    297             0,                          /* n_preallocs */
    298             tr_prefs_init,              /* instance_init */
    299             NULL,
    300         };
    301         type = g_type_register_static( GTK_TYPE_DIALOG, "TrPrefs", &info, 0 );
     147        int action;
     148        GtkTreeModel * model = gtk_combo_box_get_model( GTK_COMBO_BOX(w) );
     149        gtk_tree_model_get( model, &iter, 1, &action, -1 );
     150        tr_core_set_pref( core, key, toractionname(action) );
    302151    }
    303 
    304     return type;
    305 }
    306 
    307 static void
    308 tr_prefs_class_init( gpointer g_class, gpointer g_class_data SHUTUP )
    309 {
    310     GObjectClass * gobject_class;
    311     GParamSpec   * pspec;
    312 
    313     gobject_class = G_OBJECT_CLASS( g_class );
    314     gobject_class->set_property = tr_prefs_set_property;
    315     gobject_class->get_property = tr_prefs_get_property;
    316     gobject_class->dispose      = tr_prefs_dispose;
    317 
    318     pspec = g_param_spec_object( "parent", "Parent",
    319                                  "The parent GtkWindow.",
    320                                  GTK_TYPE_WINDOW, G_PARAM_READWRITE );
    321     g_object_class_install_property( gobject_class, PROP_PARENT, pspec );
    322 
    323     pspec = g_param_spec_object( "core", "Parent",
    324                                  "The TrCore object.",
    325                                  TR_CORE_TYPE, G_PARAM_READWRITE );
    326     g_object_class_install_property( gobject_class, PROP_CORE, pspec );
    327 }
    328 
    329 static void
    330 tr_prefs_init( GTypeInstance * instance, gpointer g_class SHUTUP )
    331 {
    332     struct checkctl * links[ ALEN( defs_bool ) ];
    333     TrPrefs     * self = ( TrPrefs * )instance;
    334     char        * title;
    335     GtkWidget   * table;
    336     GtkTooltips * tips;
    337     int           rows, ii, off;
    338 
    339     self->combomodel = makecombomodel();
    340     self->core       = NULL;
    341     self->prefwids   = g_new0( GtkWidget *, PREF_MAX_ID );
    342     self->disposed   = FALSE;
    343     self->fileselhack = FALSE;
    344 
    345     gtk_window_set_role( GTK_WINDOW( self ), "tr-prefs" );
    346     title = g_strdup_printf( _("%s Preferences"), g_get_application_name() );
    347     gtk_window_set_title( GTK_WINDOW( self ), title );
    348     g_free( title );
    349     gtk_dialog_set_has_separator( GTK_DIALOG( self ), FALSE );
    350     gtk_dialog_add_button( GTK_DIALOG( self ), GTK_STOCK_CLOSE,
    351                            GTK_RESPONSE_CLOSE );
    352     gtk_widget_set_name( GTK_WIDGET( self ), "TransmissionDialog");
    353     gtk_dialog_set_default_response( GTK_DIALOG( self ), GTK_RESPONSE_CLOSE );
    354     gtk_container_set_border_width( GTK_CONTAINER( self ), 6 );
    355     gtk_window_set_resizable( GTK_WINDOW( self ), FALSE );
    356 
    357     rows = countprefs();
    358     table = gtk_table_new( rows, 2, FALSE );
    359     gtk_table_set_col_spacings( GTK_TABLE( table ), 8 );
    360     gtk_table_set_row_spacings( GTK_TABLE( table ), 8 );
    361 
    362     tips = gtk_tooltips_new();
    363     g_object_ref( tips );
    364     gtk_object_sink( GTK_OBJECT( tips ) );
    365     gtk_tooltips_enable( tips );
    366     g_signal_connect_swapped( self, "destroy",
    367                               G_CALLBACK( g_object_unref ), tips );
    368 
    369     memset( links, 0, sizeof( links ) );
    370     makelinks( links );
    371     off = 0;
    372     for( ii = 0; PREF_MAX_ID > ii; ii++ )
    373     {
    374         if( PR_SKIP != defs[ii].status )
    375         {
    376             addwidget( self, ii, GTK_TABLE( table ), off, tips, links,
    377                        self->prefwids );
    378             off++;
    379         }
    380     }
    381     g_assert( rows == off );
    382     for( ii = 0; ALEN( links ) > ii; ii++ )
    383     {
    384         g_assert( NULL == links[ii] || NULL != links[ii]->check );
    385         if( NULL != links[ii] )
    386         {
    387             pokelink( links[ii] );
    388         }
    389     }
    390 
    391     gtk_box_pack_start_defaults( GTK_BOX( GTK_DIALOG( self )->vbox ), table );
    392     g_signal_connect( self, "response", G_CALLBACK( gotresp ), NULL );
    393     gtk_widget_show_all( table );
    394 }
    395 
    396 static void
    397 tr_prefs_set_property( GObject * object, guint property_id,
    398                       const GValue * value, GParamSpec * pspec)
    399 {
    400     TrPrefs * self = ( TrPrefs * )object;
    401 
    402     if( self->disposed )
    403     {
    404         return;
    405     }
    406 
    407     switch( property_id )
    408     {
    409         case PROP_PARENT:
    410             gtk_window_set_transient_for( GTK_WINDOW( self ),
    411                                           g_value_get_object( value ) );
    412             break;
    413         case PROP_CORE:
    414             if( NULL != self->core )
    415             {
    416                 g_signal_handler_disconnect( self->core, self->sigid );
    417                 g_object_unref( self->core );
    418             }
    419             self->core = g_value_get_object( value );
    420             if( NULL != self->core )
    421             {
    422                 g_object_ref( self->core );
    423                 self->sigid = g_signal_connect( self->core, "prefs-changed",
    424                                                 G_CALLBACK( prefschanged ),
    425                                                 self );
    426             }
    427             break;
    428         default:
    429             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
    430             break;
    431     }
    432 }
    433 
    434 static void
    435 tr_prefs_get_property( GObject * object, guint property_id,
    436                       GValue * value, GParamSpec * pspec )
    437 {
    438     TrPrefs   * self = ( TrPrefs * )object;
    439     GtkWindow * trans;
    440 
    441     if( self->disposed )
    442     {
    443         return;
    444     }
    445 
    446     switch( property_id )
    447     {
    448         case PROP_PARENT:
    449             trans = gtk_window_get_transient_for( GTK_WINDOW( self ) );
    450             g_value_set_object( value, trans );
    451             break;
    452         case PROP_CORE:
    453             g_value_set_object( value, self->core );
    454             break;
    455         default:
    456             G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
    457             break;
    458     }
    459 }
    460 
    461 static void
    462 tr_prefs_dispose( GObject * obj )
    463 {
    464     TrPrefs      * self = ( TrPrefs * )obj;
    465     GObjectClass * parent;
    466 
    467     if( self->disposed )
    468     {
    469         return;
    470     }
    471     self->disposed = TRUE;
    472 
    473     g_object_unref( self->combomodel );
    474 
    475     if( NULL != self->core )
    476     {
    477         g_signal_handler_disconnect( self->core, self->sigid );
    478         g_object_unref( self->core );
    479     }
    480 
    481     g_free( self->prefwids );
    482 
    483     /* Chain up to the parent class */
    484     parent = g_type_class_peek( g_type_parent( TR_PREFS_TYPE ) );
    485     parent->dispose( obj );
    486 }
    487 
    488 TrPrefs *
    489 tr_prefs_new( GObject * core )
    490 {
    491     return g_object_new( TR_PREFS_TYPE, "core", core, NULL );
    492 }
    493 
    494 TrPrefs *
    495 tr_prefs_new_with_parent( GObject * core, GtkWindow * parent )
    496 {
    497     return g_object_new( TR_PREFS_TYPE, "core", core, "parent", parent, NULL );
    498 }
    499 
    500 const char *
    501 tr_prefs_name( int id )
    502 {
    503     g_assert( 0 <= id && PREF_MAX_ID > id  && ALEN( defs ) == PREF_MAX_ID );
    504     return defs[id].name;
    505 }
    506 
    507 gboolean
    508 tr_prefs_get_int( int id, int * val )
    509 {
    510     const char * str;
    511     char       * end;
    512     int          ret;
    513 
    514     str = tr_prefs_get( id );
    515     if( NULL == str || '\0' == *str )
    516     {
    517         return FALSE;
    518     }
    519 
    520     errno = 0;
    521     ret = strtol( str, &end, 10 );
    522     if( 0 != errno || NULL == end || '\0' != *end )
    523     {
    524         return FALSE;
    525     }
    526     *val = ret;
    527     return TRUE;
    528 }
    529 
    530 gboolean
    531 tr_prefs_get_bool( int id, gboolean * val )
    532 {
    533     const char * str;
    534 
    535     str = tr_prefs_get( id );
    536     if( NULL == str )
    537     {
    538         return FALSE;
    539     }
    540     *val = strbool( str );
    541     return TRUE;
    542 }
    543 
    544 int
    545 tr_prefs_get_int_with_default( int id )
    546 {
    547     int ret;
    548 
    549     g_assert( 0 <= id && ALEN( defs ) > id &&
    550               G_TYPE_INT == PTYPE( id ) && ALEN( defs_int ) > id );
    551 
    552     if( tr_prefs_get_int( id, &ret ) )
    553     {
    554         return ret;
    555     }
    556     return defs_int[id].def;
    557 }
    558 
    559 gboolean
    560 tr_prefs_get_bool_with_default( int id )
    561 {
    562     gboolean ret;
    563 
    564     g_assert( 0 <= id && ALEN( defs ) > id &&
    565               G_TYPE_BOOLEAN == PTYPE( id ) && ALEN( defs_bool ) > id );
    566 
    567     if( tr_prefs_get_bool( id, &ret ) )
    568     {
    569         return ret;
    570     }
    571     return defs_bool[id].def;
    572 
    573 }
    574 
    575 static void
    576 gotresp( GtkWidget * widget, int resp SHUTUP, gpointer data SHUTUP )
    577 {
    578     gtk_widget_destroy( widget );
    579 }
    580 
    581 static int
    582 countprefs( void )
    583 {
    584     int ii, ret;
    585 
    586     g_assert( ALEN( defs ) == PREF_MAX_ID );
    587     ret = 0;
    588     for( ii = 0; PREF_MAX_ID > ii; ii++ )
    589     {
    590         if( PR_SKIP != defs[ii].status )
    591         {
    592             ret++;
    593         }
    594     }
    595 
    596     return ret;
    597 }
    598 
    599 static void
    600 makelinks( struct checkctl ** links )
    601 {
    602     int ii;
    603 
    604     g_assert( ALEN( defs ) == PREF_MAX_ID );
    605     for( ii = 0; PREF_MAX_ID > ii; ii++ )
    606     {
    607         if( PR_SKIP == defs[ii].status || G_TYPE_BOOLEAN != PTYPE( ii ) )
    608         {
    609             continue;
    610         }
    611         g_assert( ALEN( defs_bool ) > ii );
    612         if( 0 <= defs_bool[ii].link )
    613         {
    614             links[ii] = g_new0( struct checkctl, 1 );
    615         }
    616     }
    617 }
    618 
    619 static void
    620 filllinks( int id, GtkWidget * wid1, GtkWidget * wid2,
    621            struct checkctl ** links )
    622 {
    623     int ii;
    624 
    625     g_assert( ALEN( defs ) >= ALEN( defs_bool ) );
    626     for( ii = 0; ALEN( defs_bool) > ii; ii++ )
    627     {
    628         if( NULL == links[ii] )
    629         {
    630             g_assert( PR_SKIP == defs[ii].status ||
    631                       G_TYPE_BOOLEAN != PTYPE( ii ) ||
    632                       0 > defs_bool[ii].link );
    633         }
    634         else
    635         {
    636             g_assert( PR_SKIP != defs[ii].status &&
    637                       G_TYPE_BOOLEAN == PTYPE( ii ) &&
    638                       0 <= defs_bool[ii].link );
    639             if( id == defs_bool[ii].link )
    640             {
    641                 links[ii]->wids[0] = wid1;
    642                 links[ii]->wids[1] = wid2;
    643             }
    644         }
    645     }
    646 }
    647 
    648 static void
    649 pokelink( struct checkctl * link )
    650 {
    651     gboolean active;
    652 
    653     active = gtk_toggle_button_get_active( link->check );
    654     active = ( link->enables ? active : !active );
    655     gtk_widget_set_sensitive( link->wids[0], active );
    656     gtk_widget_set_sensitive( link->wids[1], active );
    657 }
    658 
    659 static void
    660 addwidget( TrPrefs * self, int id, GtkTable * table, int off,
    661            GtkTooltips * tips, struct checkctl ** links, GtkWidget ** widgets )
    662 {
    663     GType       type;
    664     GtkWidget * add1, * add2;
    665 
    666     g_assert( ALEN( defs ) > id );
    667 
    668     type = PTYPE( id );
    669     add1 = NULL;
    670     add2 = NULL;
    671     if( G_TYPE_BOOLEAN == type )
    672     {
    673         addwid_bool( self, id, tips, &add1, links, widgets );
    674     }
    675     else if( G_TYPE_INT == type )
    676     {
    677         addwid_int( self, id, tips, &add1, &add2, widgets );
    678     }
    679     else if( GTK_TYPE_FILE_CHOOSER == type )
    680     {
    681         addwid_file( self, id, tips, &add1, &add2, widgets );
    682     }
    683     else if( GTK_TYPE_COMBO_BOX == type )
    684     {
    685         addwid_combo( self, id, tips, &add1, &add2, widgets );
    686     }
    687     else
    688     {
    689         g_assert_not_reached();
    690     }
    691 
    692     g_assert( NULL != add1 );
    693     filllinks( id, add1, add2, links );
    694     if( NULL == add2 )
    695     {
    696         gtk_table_attach_defaults( table, add1, 0, 2, off, off + 1 );
    697     }
    698     else
    699     {
    700         gtk_table_attach_defaults( table, add1, 0, 1, off, off + 1 );
    701         gtk_table_attach_defaults( table, add2, 1, 2, off, off + 1 );
    702     }
    703     if( PR_DISABLED == defs[id].status )
    704     {
    705         gtk_widget_set_sensitive( add1, FALSE );
    706         if( NULL != add2 )
    707         {
    708             gtk_widget_set_sensitive( add2, FALSE );
    709         }
    710     }
    711 }
    712 
    713 /* wrap a widget in an event box with a tooltip */
    714 static GtkWidget *
    715 tipbox( GtkWidget * widget, GtkTooltips * tips, const char * tip )
    716 {
    717     GtkWidget * box;
    718 
    719     box = gtk_event_box_new();
    720     gtk_container_add( GTK_CONTAINER( box ), widget );
    721     gtk_tooltips_set_tip( tips, box, tip, "" );
    722 
    723     return box;
    724 }
    725 
    726 static void
    727 addwid_bool( TrPrefs * self, int id, GtkTooltips * tips,
    728              GtkWidget ** wid1, struct checkctl ** links, GtkWidget ** wids )
    729 {
    730     GtkWidget  * check;
    731     gboolean     active;
    732 
    733     g_assert( ALEN( defs ) > id && G_TYPE_BOOLEAN == PTYPE( id ) );
    734     check = gtk_check_button_new_with_mnemonic( gettext( defs[id].label ) );
    735     wids[id] = check;
    736     gtk_tooltips_set_tip( tips, check, gettext( defs[id].tip ), "" );
    737     if( 0 > defs_bool[id].link )
    738     {
    739         g_assert( NULL == links[id] );
    740     }
    741     else
    742     {
    743         links[id]->check = GTK_TOGGLE_BUTTON( check );
    744         links[id]->enables = defs_bool[id].enables;
    745         g_object_set_data_full( G_OBJECT( check ), PREF_CHECK_LINK,
    746                                 links[id], g_free );
    747     }
    748     active = tr_prefs_get_bool_with_default( id );
    749     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check ), active );
    750     SETPREFID( check, id );
    751     g_signal_connect( check, "clicked", G_CALLBACK( checkclick ), self );
    752 
    753     *wid1 = check;
    754 }
    755 
    756 static void
    757 checkclick( GtkWidget * widget, gpointer data )
    758 {
    759     TrPrefs         * self;
    760     struct checkctl * link;
    761     int               id;
    762     gboolean          active;
    763 
    764     TR_IS_PREFS( data );
    765     self = TR_PREFS( data );
    766     link = g_object_get_data( G_OBJECT( widget ), PREF_CHECK_LINK );
    767     GETPREFID( widget, id );
    768 
    769     if( NULL != link )
    770     {
    771         pokelink( link );
    772     }
    773 
    774     active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( widget ) );
    775     tr_core_set_pref_bool( TR_CORE( self->core ), id, active );
    776 }
    777 
    778 static void
    779 addwid_int( TrPrefs * self, int id, GtkTooltips * tips,
    780             GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids )
    781 {
    782     GtkWidget * spin, * label;
    783     int         val, * last;
    784 
    785     g_assert( ALEN( defs ) > id && G_TYPE_INT == PTYPE( id ) );
    786     spin = gtk_spin_button_new_with_range( defs_int[id].min,
    787                                            defs_int[id].max, 1 );
    788     wids[id] = spin;
    789     label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) );
    790     gtk_label_set_mnemonic_widget( GTK_LABEL( label ), spin );
    791     gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 );
    792     gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin ), TRUE );
    793     gtk_tooltips_set_tip( tips, spin, gettext( defs[id].tip ), "" );
    794     val = tr_prefs_get_int_with_default( id );
    795     gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin ), val );
    796     last = g_new( int, 1 );
    797     *last = val;
    798     g_object_set_data_full( G_OBJECT( spin ), PREF_SPIN_LAST, last, g_free );
    799     SETPREFID( spin, id );
    800     /* I don't trust that focus-out-event will always work,
    801        so save pref on widget destruction too */
    802     g_signal_connect( spin, "focus-out-event", G_CALLBACK( spinfocus ), self );
    803     g_signal_connect( spin, "destroy", G_CALLBACK( spindie ), self );
    804 
    805     *wid1 = tipbox( label, tips, gettext( defs[id].tip ) );
    806     *wid2 = spin;
    807 }
    808 
    809 static gboolean
    810 spinfocus( GtkWidget * widget, GdkEventFocus *event SHUTUP, gpointer data )
    811 {
    812     TrPrefs * self;
    813     int     * last, id, cur;
    814 
    815     TR_IS_PREFS( data );
    816     self = TR_PREFS( data );
    817     last = g_object_get_data( G_OBJECT( widget ), PREF_SPIN_LAST );
    818     GETPREFID( widget, id );
    819     cur = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( widget ) );
    820 
    821     if( cur != *last )
    822     {
    823         tr_core_set_pref_int( TR_CORE( self->core ), id, cur );
    824         *last = cur;
    825     }
    826 
    827     /* continue propagating the event */
    828     return FALSE;
    829 }
    830 
    831 static void
    832 spindie( GtkWidget * widget, gpointer data )
    833 {
    834     spinfocus( widget, NULL, data );
    835 }
    836 
    837 static void
    838 addwid_file( TrPrefs * self, int id, GtkTooltips * tips,
    839              GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids )
    840 {
    841     GtkWidget  * file, * label;
    842     const char * pref;
    843 
    844     g_assert( ALEN( defs ) > id && GTK_TYPE_FILE_CHOOSER == PTYPE( id ) );
    845     file = gtk_file_chooser_button_new( gettext( defs_file[id].title ),
    846                                         defs_file[id].act );
    847     wids[id] = file;
    848     label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) );
    849     gtk_label_set_mnemonic_widget( GTK_LABEL( label ), file );
    850     gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 );
    851     pref = tr_prefs_get( id );
    852     if( NULL == pref )
    853     {
    854         pref = defs_file[id].getdef();
    855     }
    856     gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( file ), pref );
    857     SETPREFID( file, id );
    858     g_signal_connect( file, "selection-changed",
    859                       G_CALLBACK( filechosen ), self );
    860 
    861     *wid1 = tipbox( label, tips, gettext( defs[id].tip ) );
    862     *wid2 = tipbox( file,  tips, gettext( defs[id].tip ) );
    863 }
    864 
    865 static void
    866 filechosen( GtkWidget * widget, gpointer data )
    867 {
    868     TrPrefs    * self;
    869     char       * dir;
    870     int          id;
    871 
    872     TR_IS_PREFS( data );
    873     self = TR_PREFS( data );
    874     dir = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( widget ) );
    875     GETPREFID( widget, id );
    876     self->fileselhack = TRUE;
    877     tr_core_set_pref( TR_CORE( self->core ), id, dir );
    878     self->fileselhack = FALSE;
    879     g_free( dir );
    880 }
    881 
    882 static GtkTreeModel *
    883 makecombomodel( void )
    884 {
    885     GtkListStore * list;
    886     GtkTreeIter    iter;
    887 
    888     /* create the model used by the two popup menus */
    889     list = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
    890     gtk_list_store_append( list, &iter );
    891     gtk_list_store_set( list, &iter, 1, TR_TOR_LEAVE, 0,
     152}
     153
     154static GtkWidget*
     155new_action_combo( const char * key, gpointer core )
     156{
     157    GtkTreeIter iter;
     158    GtkCellRenderer * rend;
     159    GtkListStore * model;
     160    GtkWidget * w;
     161
     162    model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
     163    gtk_list_store_append( model, &iter );
     164    gtk_list_store_set( model, &iter, 1, TR_TOR_LEAVE, 0,
    892165                        _("Use the torrent file where it is"), -1 );
    893     gtk_list_store_append( list, &iter );
    894     gtk_list_store_set( list, &iter, 1, TR_TOR_COPY, 0,
     166    gtk_list_store_append( model, &iter );
     167    gtk_list_store_set( model, &iter, 1, TR_TOR_COPY, 0,
    895168                        _("Keep a copy of the torrent file"), -1 );
    896     gtk_list_store_append( list, &iter );
    897     gtk_list_store_set( list, &iter, 1, TR_TOR_MOVE, 0,
     169    gtk_list_store_append( model, &iter );
     170    gtk_list_store_set( model, &iter, 1, TR_TOR_MOVE, 0,
    898171                        _("Keep a copy and remove the original"), -1 );
    899172
    900     return GTK_TREE_MODEL( list );
    901 }
    902 
    903 static void
    904 addwid_combo( TrPrefs * self, int id, GtkTooltips * tips,
    905               GtkWidget ** wid1, GtkWidget ** wid2, GtkWidget ** wids )
    906 {
    907     GtkWidget       * combo, * label;
    908     GtkCellRenderer * rend;
    909 
    910     g_assert( ALEN( defs ) > id && GTK_TYPE_COMBO_BOX == PTYPE( id ) );
    911     combo = gtk_combo_box_new();
    912     wids[id] = combo;
    913     label = gtk_label_new_with_mnemonic( gettext( defs[id].label ) );
    914     gtk_label_set_mnemonic_widget( GTK_LABEL( label ), combo );
    915     gtk_misc_set_alignment( GTK_MISC( label ), 0, .5 );
    916     gtk_combo_box_set_model( GTK_COMBO_BOX( combo ), self->combomodel );
    917     rend = gtk_cell_renderer_text_new();
    918     gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( combo ), rend, TRUE );
    919     gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT( combo ), rend, "text", 0 );
    920 
    921     setcombosel( self->combomodel, GTK_COMBO_BOX( combo ), id );
    922     SETPREFID( combo, id );
    923     g_signal_connect( combo, "changed", G_CALLBACK( combochosen ), self );
    924 
    925     *wid1 = tipbox( label, tips, gettext( defs[id].tip ) );
    926     *wid2 = tipbox( combo, tips, gettext( defs[id].tip ) );
    927 }
    928 
    929 static void
    930 setcombosel( GtkTreeModel * model, GtkComboBox * combo, int id )
    931 {
    932     GtkTreeIter            iter;
    933     enum tr_torrent_action prefsact, modelact;
    934 
    935     prefsact = toraddaction( tr_prefs_get( id ) );
    936     if( gtk_tree_model_get_iter_first( model, &iter ) )
    937     {
    938         do
    939         {
    940             gtk_tree_model_get( model, &iter, 1, &modelact, -1 );
    941             if( modelact == prefsact )
    942             {
    943                 gtk_combo_box_set_active_iter( combo, &iter );
    944                 break;
    945             }
    946         }
    947         while( gtk_tree_model_iter_next( model, &iter ) );
    948     }
    949 }
    950 
    951 static void
    952 combochosen( GtkWidget * widget, gpointer data )
    953 {
    954     TrPrefs      * self;
    955     GtkTreeIter    iter;
    956     GtkTreeModel * model;
    957     enum tr_torrent_action action;
    958     int            id;
    959 
    960     TR_IS_PREFS( data );
    961     self = TR_PREFS( data );
    962     if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX( widget ), &iter ) )
    963     {
    964         model = gtk_combo_box_get_model( GTK_COMBO_BOX( widget ) );
    965         gtk_tree_model_get( model, &iter, 1, &action, -1 );
    966         GETPREFID( widget, id );
    967         tr_core_set_pref( TR_CORE( self->core ), id, toractionname( action ) );
    968     }
    969 }
    970 
    971 static void
    972 prefschanged( TrCore * core SHUTUP, int id, gpointer data )
    973 {
    974     TrPrefs    * prefs;
    975     GtkWidget  * wid;
    976     gboolean     boolval;
    977     int          intval;
    978     const char * strval;
    979 
    980     TR_IS_PREFS( data );
    981     prefs = TR_PREFS( data );
    982 
    983     g_assert( ALEN( defs ) > id && 0 <= id );
    984 
    985     wid = prefs->prefwids[id];
    986 
    987     if( G_TYPE_BOOLEAN == PTYPE( id ) )
    988     {
    989         boolval = tr_prefs_get_bool_with_default( id );
    990         if( boolval !=
    991             gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( wid ) ) )
    992         {
    993             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( wid ), boolval );
    994         }
    995     }
    996     else if( G_TYPE_INT == PTYPE( id ) )
    997     {
    998         intval = tr_prefs_get_int_with_default( id );
    999         if( intval !=
    1000             gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( wid ) ) )
    1001         {
    1002             gtk_spin_button_set_value( GTK_SPIN_BUTTON( wid ), intval );
    1003         }
    1004     }
    1005     else if( GTK_TYPE_FILE_CHOOSER == PTYPE( id ) )
    1006     {
    1007         strval = tr_prefs_get( id );
    1008         if( !prefs->fileselhack && strval !=
    1009             gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( wid ) ) )
    1010         {
    1011             gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( wid ),
    1012                                                  strval );
    1013         }
    1014     }
    1015     else if( GTK_TYPE_COMBO_BOX == PTYPE( id ) )
    1016     {
    1017         setcombosel( prefs->combomodel, GTK_COMBO_BOX( wid ), id );
    1018     }
    1019     else
    1020     {
    1021         g_assert_not_reached();
    1022     }
    1023 }
     173    w = gtk_combo_box_new_with_model( GTK_TREE_MODEL(model) );
     174    gtk_combo_box_set_active( GTK_COMBO_BOX(w), pref_int_get(key) );
     175    g_object_set_data_full( G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free );
     176    rend = gtk_cell_renderer_text_new( );
     177    gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(w), rend, TRUE );
     178    gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(w), rend, "text", 0 );
     179    g_signal_connect( w, "changed", G_CALLBACK(action_cb), core );
     180
     181    return w;
     182}
     183
     184GtkWidget *
     185tr_prefs_dialog_new( GObject * core, GtkWindow * parent )
     186{
     187    int row = 0;
     188    GtkWidget * t;
     189    GtkWidget * w;
     190    GtkWidget * l;
     191    GtkWidget * dialog = gtk_dialog_new_with_buttons( _("Transmission: Preferences"), parent,
     192                                                      GTK_DIALOG_DESTROY_WITH_PARENT,
     193                                                      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
     194                                                      NULL );
     195    gtk_window_set_role( GTK_WINDOW(dialog), "transmission-preferences-dialog" );
     196    g_signal_connect( dialog, "response", G_CALLBACK(response_cb), core );
     197
     198    t = hig_workarea_create ();
     199
     200    hig_workarea_add_section_title (t, &row, _("Speed Limits"));
     201    hig_workarea_add_section_spacer (t, row, 4);
     202
     203        w = new_check_button( _("_Limit Upload Speed"), PREF_KEY_UL_LIMIT_ENABLED, core );
     204        hig_workarea_add_wide_control( t, &row, w );
     205
     206        w = new_spin_button( PREF_KEY_UL_LIMIT, core, 20, INT_MAX );
     207        l = hig_workarea_add_row( t, &row, _("Maximum _Upload Speed (KiB/s)"), w, NULL );
     208       
     209        w = new_check_button( _("Li_mit Download Speed"), PREF_KEY_DL_LIMIT_ENABLED, core );
     210        hig_workarea_add_wide_control( t, &row, w );
     211
     212        w = new_spin_button( PREF_KEY_DL_LIMIT, core, 1, INT_MAX );
     213        l = hig_workarea_add_row( t, &row, _("Maximum _Download Speed (KiB/s)"), w, NULL );
     214
     215    hig_workarea_add_section_divider( t, &row );
     216    hig_workarea_add_section_title (t, &row, _("Downloads"));
     217    hig_workarea_add_section_spacer (t, row, 4);
     218
     219        w = new_check_button( _("Al_ways prompt for download directory"), PREF_KEY_DIR_ASK, core );
     220        hig_workarea_add_wide_control( t, &row, w );
     221
     222        w = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core );
     223        l = hig_workarea_add_row( t, &row, _("Download Di_rectory"), w, NULL );
     224
     225        w = new_action_combo( PREF_KEY_ADDSTD, core );
     226        l = hig_workarea_add_row( t, &row, _("For torrents added _normally:"), w, NULL );
     227
     228        w = new_action_combo( PREF_KEY_ADDIPC, core );
     229        l = hig_workarea_add_row( t, &row, _("For torrents added from _command-line:"), w, NULL );
     230
     231    hig_workarea_add_section_divider( t, &row );
     232    hig_workarea_add_section_title (t, &row, _("Network"));
     233    hig_workarea_add_section_spacer (t, row, 2);
     234       
     235        w = new_check_button( _("_Automatic Port Mapping via NAT-PMP or UPnP"), PREF_KEY_NAT, core );
     236        hig_workarea_add_wide_control( t, &row, w );
     237
     238        w = new_spin_button( PREF_KEY_PORT, core, 1, INT_MAX );
     239        l = hig_workarea_add_row( t, &row, _("Listening _Port"), w, NULL );
     240
     241    hig_workarea_add_section_divider( t, &row );
     242    hig_workarea_add_section_title (t, &row, _("Options"));
     243    hig_workarea_add_section_spacer (t, row, 3);
     244       
     245        w = new_check_button( _("Use Peer _Exchange if Possible"), PREF_KEY_PEX, core );
     246        hig_workarea_add_wide_control( t, &row, w );
     247       
     248        w = new_check_button( _("Display an Icon in the System _Tray"), PREF_KEY_SYSTRAY, core );
     249        hig_workarea_add_wide_control( t, &row, w );
     250       
     251        w = new_check_button( _("Confirm _quit"), PREF_KEY_ASKQUIT, core );
     252        hig_workarea_add_wide_control( t, &row, w );
     253
     254    hig_workarea_finish (t, &row);
     255    gtk_box_pack_start_defaults( GTK_BOX(GTK_DIALOG(dialog)->vbox), t );
     256    gtk_widget_show_all( GTK_DIALOG(dialog)->vbox );
     257    return dialog;
     258}
  • trunk/gtk/tr_prefs.h

    r1938 r3206  
    1 /******************************************************************************
    2  * $Id$
     1/*
     2 * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
    33 *
    4  * Copyright (c) 2007 Transmission authors and contributors
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the "Software"),
    8  * to deal in the Software without restriction, including without limitation
    9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    10  * and/or sell copies of the Software, and to permit persons to whom the
    11  * Software is furnished to do so, subject to the following conditions:
    12  *
    13  * The above copyright notice and this permission notice shall be included in
    14  * all copies or substantial portions of the Software.
    15  *
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    22  * DEALINGS IN THE SOFTWARE.
    23  *****************************************************************************/
     4 * This file is licensed by the GPL version 2.  Works owned by the
     5 * Transmission project are granted a special exemption to clause 2(b)
     6 * so that the bulk of its code can remain under the MIT license.
     7 * This exemption does not extend to derived works not owned by
     8 * the Transmission project.
     9 *
     10 * $Id:$
     11 */
    2412
    2513#ifndef TR_PREFS_H
     
    2816#include <gtk/gtk.h>
    2917
    30 #include "conf.h"
     18GtkWidget * tr_prefs_dialog_new( GObject * core, GtkWindow * parent );
    3119
    32 #define TR_PREFS_TYPE             ( tr_prefs_get_type() )
     20#define PREF_KEY_DL_LIMIT_ENABLED  "download-limit-enabled"
     21#define PREF_KEY_DL_LIMIT          "download-limit"
     22#define PREF_KEY_UL_LIMIT_ENABLED  "upload-limit-enabled"
     23#define PREF_KEY_UL_LIMIT          "upload-limit"
     24#define PREF_KEY_DIR_ASK           "prompt-for-download-directory"
     25#define PREF_KEY_DIR_DEFAULT       "default-download-directory"
     26#define PREF_KEY_ADDSTD            "add-behavior-standard"
     27#define PREF_KEY_ADDIPC            "add-behavior-ipc"
     28#define PREF_KEY_PORT              "listening-port"
     29#define PREF_KEY_NAT               "nat-traversal-enabled"
     30#define PREF_KEY_PEX               "pex-enabled"
     31#define PREF_KEY_SYSTRAY           "system-tray-icon-enabled"
     32#define PREF_KEY_ASKQUIT           "prompt-before-exit"
     33#define PREF_KEY_MSGLEVEL          "debug-message-level"
    3334
    34 #define TR_PREFS( obj ) \
    35   ( G_TYPE_CHECK_INSTANCE_CAST( (obj),   TR_PREFS_TYPE, TrPrefs ) )
     35void tr_prefs_init_global( void );
    3636
    37 #define TR_PREFS_CLASS( class ) \
    38   ( G_TYPE_CHECK_CLASS_CAST(    (class), TR_PREFS_TYPE, TrPrefsClass ) )
    39 
    40 #define TR_IS_PREFS( obj ) \
    41   ( G_TYPE_CHECK_INSTANCE_TYPE( (obj),   TR_PREFS_TYPE ) )
    42 
    43 #define TR_IS_PREFS_CLASS( class ) \
    44   ( G_TYPE_CHECK_CLASS_TYPE(    (class), TR_PREFS_TYPE ) )
    45 
    46 #define TR_PREFS_GET_CLASS( obj ) \
    47   ( G_TYPE_INSTANCE_GET_CLASS(  (obj),   TR_PREFS_TYPE, TrPrefsClass ) )
    48 
    49 typedef struct _TrPrefs TrPrefs;
    50 typedef struct _TrPrefsClass TrPrefsClass;
    51 
    52 /* treat the contents of this structure as private */
    53 struct _TrPrefs
    54 {
    55     GtkDialog      parent;
    56     GtkTreeModel * combomodel;
    57     GObject      * core;
    58     gulong         sigid;
    59     GtkWidget   ** prefwids;
    60     gboolean       fileselhack;
    61     gboolean       disposed;
    62 };
    63 
    64 struct _TrPrefsClass
    65 {
    66     GtkDialogClass parent;
    67 };
    68 
    69 GType
    70 tr_prefs_get_type( void );
    71 
    72 TrPrefs *
    73 tr_prefs_new( GObject * core );
    74 
    75 TrPrefs *
    76 tr_prefs_new_with_parent( GObject * core, GtkWindow * parent );
    77 
    78 /* please keep this in sync with defs in tr_prefs.c */
    79 enum
    80 {
    81     PREF_ID_USEDOWNLIMIT = 0,
    82     PREF_ID_DOWNLIMIT,
    83     PREF_ID_USEUPLIMIT,
    84     PREF_ID_UPLIMIT,
    85     PREF_ID_ASKDIR,
    86     PREF_ID_DIR,
    87     PREF_ID_PORT,
    88     PREF_ID_NAT,
    89     PREF_ID_PEX,
    90     PREF_ID_ICON,
    91     PREF_ID_ASKQUIT,
    92     PREF_ID_ADDSTD,
    93     PREF_ID_ADDIPC,
    94     PREF_ID_MSGLEVEL,
    95     PREF_MAX_ID
    96 };
    97 
    98 const char *
    99 tr_prefs_name( int id );
    100 
    101 /* convenience macros and functions for reading pref by id */
    102 #define tr_prefs_get( id )      cf_getpref( tr_prefs_name( (id) ) )
    103 
    104 gboolean
    105 tr_prefs_get_int( int id, int * val );
    106 
    107 gboolean
    108 tr_prefs_get_bool( int id, gboolean * val );
    109 
    110 int
    111 tr_prefs_get_int_with_default( int id );
    112 
    113 gboolean
    114 tr_prefs_get_bool_with_default( int id );
     37int  tr_prefs_get_action( const char * key );
     38void tr_prefs_set_action( const char * key, int action );
    11539
    11640#endif
  • trunk/gtk/tr_torrent.c

    r3111 r3206  
    3434#include "tr_prefs.h"
    3535#include "tr_torrent.h"
     36#include "conf.h"
    3637#include "util.h"
    3738
     
    284285maketorrent( tr_torrent * handle )
    285286{
    286     tr_torrentDisablePex( handle,
    287                           !tr_prefs_get_bool_with_default( PREF_ID_PEX ) );
     287    tr_torrentDisablePex( handle, !pref_flag_get( PREF_KEY_PEX ) );
    288288
    289289    return g_object_new( TR_TORRENT_TYPE,
  • trunk/gtk/util.c

    r2392 r3206  
    3636#include "tr_prefs.h"
    3737#include "tr_torrent.h"
     38#include "conf.h"
    3839#include "util.h"
    3940
     
    5051    if( b ) return -1;
    5152    return 0;
    52 }
    53 
    54 gboolean
    55 strbool( const char * str )
    56 {
    57   if( !str )
    58     return FALSE;
    59 
    60   switch(str[0]) {
    61     case 'y':
    62     case 'Y':
    63     case '1':
    64     case 'j':
    65     case 'e':
    66       return TRUE;
    67     default:
    68       if(0 == g_ascii_strcasecmp("on", str))
    69         return TRUE;
    70       break;
    71   }
    72 
    73   return FALSE;
    7453}
    7554
     
    315294}
    316295
    317 const char *
     296char *
    318297getdownloaddir( void )
    319298{
    320299    static char * wd = NULL;
    321     const char * dir = tr_prefs_get( PREF_ID_DIR );
    322     if (NULL == dir) {
    323       if (NULL == wd)
    324         wd = g_get_current_dir();
    325       dir = wd;
     300    char * dir = pref_string_get( PREF_KEY_DIR_DEFAULT );
     301    if ( dir == NULL ) {
     302        if( wd == NULL )
     303            wd = g_get_current_dir();
     304        dir = g_strdup( wd );
    326305    }
    327306    return dir;
  • trunk/gtk/util.h

    r2505 r3206  
    4444/* used for a callback function with a data parameter */
    4545typedef void (*callbackfunc_t)(void*);
    46 
    47 /* try to interpret a string as a textual representation of a boolean */
    48 /* note that this isn't localized */
    49 gboolean
    50 strbool(const char *str);
    5146
    5247/* return a human-readable string for the size given in bytes.
     
    107102
    108103/* retrieve the global download directory */
    109 const char *
     104char *
    110105getdownloaddir( void );
    111106
Note: See TracChangeset for help on using the changeset viewer.