Changeset 69


Ignore:
Timestamp:
Jan 30, 2006, 3:12:06 PM (15 years ago)
Author:
joshe
Message:

Merge from trunk up to rev 68.

Location:
branches/oneport
Files:
2 deleted
29 edited
12 copied

Legend:

Unmodified
Added
Removed
  • branches/oneport/Jamrules

    r26 r69  
    99VERSION_MINOR  = 4 ;
    1010# VERSION_STRING = $(VERSION_MAJOR).$(VERSION_MINOR) ;
    11 VERSION_STRING = 0.5-cvs ;
     11VERSION_STRING = 0.5-svn ;
    1212
    1313DEFINES += VERSION_MAJOR=$(VERSION_MAJOR)
  • branches/oneport/configure

    r21 r69  
    162162  FreeBSD)
    163163    DEFINES="$DEFINES SYS_FREEBSD"
    164     LINKLIBS="$LINKLIBS -pthread"
     164    LINKLIBS="$LINKLIBS -pthread -lm"
    165165    ;;
    166166
    167167  NetBSD)
    168168    DEFINES="$DEFINES SYS_NETBSD"
    169     LINKLIBS="$LINKLIBS -lpthread"
     169    LINKLIBS="$LINKLIBS -lpthread -lm"
    170170    ;;
    171171
    172172  Linux)
    173173    DEFINES="$DEFINES SYS_LINUX"
    174     LINKLIBS="$LINKLIBS -lpthread"
     174    LINKLIBS="$LINKLIBS -lpthread -lm"
    175175    ;;
    176176
     
    180180esac
    181181echo "System:  $SYSTEM"
     182
     183#
     184# Mac OS X check for the Universal SDK
     185#
     186if [ $SYSTEM = Darwin -a ! -d /Developer/SDKs/MacOSX10.4u.sdk ]; then
     187  echo
     188  echo "You need to install the Universal SDK in order to build Transmission:"
     189  echo "  Get your Xcode CD or package"
     190  echo "  Restart the install"
     191  echo "  When it gets to \"Installation Type\", select \"Customize\""
     192  echo "  Select \"Mac OS X 10.4 (Universal) SDL\" under \"Cross Development\""
     193  echo "  Finish the install."
     194  exit 1
     195fi
    182196
    183197#
  • branches/oneport/libtransmission/Jamfile

    r14 r69  
    33LIBTRANSMISSION_SRC =
    44    transmission.c bencode.c net.c tracker.c peer.c inout.c
    5     metainfo.c sha1.c utils.c upload.c fdlimit.c clients.c
    6     completion.c platform.c ;
     5    metainfo.c sha1.c utils.c fdlimit.c clients.c completion.c
     6    platform.c ratecontrol.c choking.c ;
    77
    88Library       libtransmission.a       : $(LIBTRANSMISSION_SRC) ;
  • branches/oneport/libtransmission/choking.c

    r63 r69  
    2121 *****************************************************************************/
    2222
     23#include <math.h>
    2324#include "transmission.h"
    24 
    25 #define MAX_HISTORY 30
    2625
    2726struct tr_choking_s
     
    2928    tr_lock_t     lock;
    3029    tr_handle_t * h;
    31     int           slotsMax;
    32     int           slotsUsed;
     30    int           slots;
    3331};
    3432
     
    3735    tr_choking_t * c;
    3836
    39     c           = calloc( sizeof( tr_choking_t ), 1 );
    40     c->h        = h;
    41     c->slotsMax = 4242;
     37    c        = calloc( sizeof( tr_choking_t ), 1 );
     38    c->h     = h;
     39    c->slots = 4242;
    4240    tr_lockInit( &c->lock );
    4341
     
    4947    tr_lockLock( &c->lock );
    5048    if( limit < 0 )
    51         c->slotsMax = 4242;
     49        c->slots = 4242;
    5250    else
    53         c->slotsMax = lrintf( sqrt( 2 * limit ) );
     51        c->slots = lrintf( sqrt( 2 * limit ) );
    5452    tr_lockUnlock( &c->lock );
     53}
     54
     55static inline void sortPeers( tr_peer_t ** peers, int count )
     56{
     57    int i, j;
     58    tr_peer_t * tmp;
     59
     60    for( i = count - 1; i > 0; i-- )
     61        for( j = 0; j < i; j++ )
     62        {
     63            if( tr_peerDownloadRate( peers[j] ) >
     64                    tr_peerDownloadRate( peers[j+1] ) )
     65            {
     66                tmp        = peers[j];
     67                peers[j]   = peers[j+1];
     68                peers[j+1] = tmp;
     69            }
     70        }
    5571}
    5672
    5773void tr_chokingPulse( tr_choking_t * c )
    5874{
     75    int i, j, peersTotalCount;
     76    tr_peer_t * peer;
     77    tr_peer_t ** peersCanChoke, ** peersCanUnchoke;
     78    int peersCanChokeCount, peersCanUnchokeCount, unchokedCount;
     79    tr_torrent_t * tor;
     80    uint64_t now = tr_date();
     81
    5982    tr_lockLock( &c->lock );
     83
     84    /* Lock all torrents and get the total number of peers */
     85    peersTotalCount = 0;
     86    for( i = 0; i < c->h->torrentCount; i++ )
     87    {
     88        tor = c->h->torrents[i];
     89        tr_lockLock( &tor->lock );
     90        peersTotalCount += tor->peerCount;
     91    }
     92
     93    peersCanChoke   = malloc( peersTotalCount * sizeof( tr_peer_t * ) );
     94    peersCanUnchoke = malloc( peersTotalCount * sizeof( tr_peer_t * ) );
     95    peersCanChokeCount   = 0;
     96    peersCanUnchokeCount = 0;
     97    unchokedCount        = 0;
     98
     99    /* Build two lists of interested peers: those who may choke,
     100       those who may unchoke */
     101    for( i = 0; i < c->h->torrentCount; i++ )
     102    {
     103        tor = c->h->torrents[i];
     104        for( j = 0; j < tor->peerCount; j++ )
     105        {
     106            peer = tor->peers[j];
     107
     108            if( !tr_peerIsConnected( peer ) )
     109                continue;
     110
     111            if( !tr_peerIsInterested( peer ) )
     112            {
     113                if( tr_peerIsUnchoked( peer ) )
     114                    tr_peerChoke( peer );
     115                continue;
     116            }
     117
     118            if( tr_peerIsUnchoked( peer ) )
     119            {
     120                unchokedCount++;
     121                if( tr_peerLastChoke( peer ) + 10000 < now )
     122                    peersCanChoke[peersCanChokeCount++] = peer;
     123            }
     124            else
     125            {
     126                if( tr_peerLastChoke( peer ) + 10000 < now )
     127                    peersCanUnchoke[peersCanUnchokeCount++] = peer;
     128            }
     129        }
     130    }
     131
     132    sortPeers( peersCanChoke, peersCanChokeCount );
     133    sortPeers( peersCanUnchoke, peersCanUnchokeCount );
     134
     135    if( unchokedCount > c->slots )
     136    {
     137        int willChoke;
     138        willChoke = MIN( peersCanChokeCount, unchokedCount - c->slots );
     139        for( i = 0; i < willChoke; i++ )
     140            tr_peerChoke( peersCanChoke[i] );
     141        peersCanChokeCount -= willChoke;
     142        memmove( &peersCanChoke[0], &peersCanChoke[willChoke],
     143                 peersCanChokeCount );
     144    }
     145    else if( unchokedCount < c->slots )
     146    {
     147        int willUnchoke;
     148        willUnchoke = MIN( peersCanUnchokeCount, c->slots - unchokedCount );
     149        for( i = 0; i < willUnchoke; i++ )
     150            tr_peerUnchoke( peersCanUnchoke[peersCanUnchokeCount - i - 1] );
     151        peersCanUnchokeCount -= willUnchoke;
     152    }
     153
     154    while( peersCanChokeCount > 0 && peersCanUnchokeCount > 0 )
     155    {
     156        if( tr_peerDownloadRate( peersCanUnchoke[peersCanUnchokeCount - 1] )
     157                > tr_peerDownloadRate( peersCanChoke[0] ) )
     158            break;
     159
     160        tr_peerChoke( peersCanChoke[0] );
     161        tr_peerUnchoke( peersCanUnchoke[peersCanUnchokeCount - 1] );
     162        peersCanChokeCount--;
     163        peersCanUnchokeCount--;
     164        memmove( &peersCanChoke[0], &peersCanChoke[1], peersCanChokeCount );
     165    }
     166
     167    free( peersCanChoke );
     168    free( peersCanUnchoke );
     169
     170    /* Unlock all torrents */
     171    for( i = 0; i < c->h->torrentCount; i++ )
     172    {
     173        tr_lockUnlock( &c->h->torrents[i]->lock );
     174    }
     175
    60176    tr_lockUnlock( &c->lock );
    61177}
  • branches/oneport/libtransmission/fastresume.h

    r47 r69  
    127127
    128128    /* write download and upload totals */
    129     fwrite( &tor->downloaded[9], 8, 1, file );
    130     fwrite( &tor->uploaded[9], 8, 1, file );
     129    fwrite( &tor->downloaded, 8, 1, file );
     130    fwrite( &tor->uploaded, 8, 1, file );
    131131
    132132    /* Write file mtimes */
     
    209209    {
    210210        /* read download and upload totals */
    211         fread( &tor->downloaded[9], 8, 1, file );
    212         fread( &tor->uploaded[9], 8, 1, file );
     211        fread( &tor->downloaded, 8, 1, file );
     212        fread( &tor->uploaded, 8, 1, file );
    213213    }
    214214
  • branches/oneport/libtransmission/inout.c

    r43 r69  
    391391    {
    392392        /* Should not happen */
    393         tr_err( "readOrWriteBytes: offset out of range" );
     393        tr_err( "readOrWriteBytes: offset out of range (%lld, %d, %d)",
     394                offset, size, write );
    394395        goto fail;
    395396    }
  • branches/oneport/libtransmission/internal.h

    r26 r69  
    9494#include "net.h"
    9595#include "inout.h"
    96 #include "upload.h"
     96#include "ratecontrol.h"
    9797#include "clients.h"
     98#include "choking.h"
    9899
    99100struct tr_torrent_s
     
    101102    tr_info_t info;
    102103
    103     tr_upload_t     * upload;
    104     tr_fd_t         * fdlimit;
     104    tr_ratecontrol_t * globalUpload;
     105    tr_ratecontrol_t * globalDownload;
     106    tr_ratecontrol_t * upload;
     107    tr_ratecontrol_t * download;
     108    tr_fd_t          * fdlimit;
    105109
    106110    int               status;
     
    144148    tr_peer_t       * peers[TR_MAX_PEER_COUNT];
    145149
    146     uint64_t          dates[10];
    147     uint64_t          downloaded[10];
    148     uint64_t          uploaded[10];
     150    uint64_t          date;
     151    uint64_t          downloaded;
     152    uint64_t          uploaded;
    149153};
    150154
     
    157161    tr_torrent_t * torrents[TR_MAX_TORRENT_COUNT];
    158162
    159     tr_upload_t  * upload;
     163    tr_ratecontrol_t * upload;
     164    tr_ratecontrol_t * download;
    160165    tr_fd_t      * fdlimit;
     166    tr_choking_t * choking;
    161167
    162168    int            bindPort;
  • branches/oneport/libtransmission/peer.c

    r26 r69  
    5454    char           peerInterested;
    5555
     56    uint64_t       lastChoke;
     57
    5658    uint8_t        id[20];
    5759
     
    8284    uint64_t       outDate;
    8385    int            outSlow;
     86
     87    tr_ratecontrol_t * download;
    8488};
    8589
     
    173177        tr_fdSocketClosed( fdlimit, 0 );
    174178    }
     179    tr_rcClose( peer->download );
    175180    free( peer );
    176181}
     
    195200        block = tr_block( r->index,r->begin );
    196201        tr_cpDownloaderRem( tor->completion, block );
    197     }
    198     if( !peer->amChoking )
    199     {
    200         tr_uploadChoked( tor->upload );
    201202    }
    202203    tr_peerDestroy( tor->fdlimit, peer );
     
    243244        if( NULL != tor )
    244245        {
    245             if( parseBuf( tor, peer, ret ) )
     246            tr_rcTransferred( peer->download, ret );
     247            tr_rcTransferred( tor->download, ret );
     248            tr_rcTransferred( tor->globalDownload, ret );
     249            if( parseBuf( tor, peer ) )
    246250            {
    247251                return 1;
     
    281285    tr_peer_t * peer;
    282286
    283     tor->dates[9] = tr_date();
    284     if( tor->dates[9] > tor->dates[8] + 1000 )
    285     {
    286         memmove( &tor->downloaded[0], &tor->downloaded[1],
    287                  9 * sizeof( uint64_t ) );
    288         memmove( &tor->uploaded[0], &tor->uploaded[1],
    289                  9 * sizeof( uint64_t ) );
    290         memmove( &tor->dates[0], &tor->dates[1],
    291                  9 * sizeof( uint64_t ) );
     287    if( tr_date() > tor->date + 1000 )
     288    {
     289        tor->date = tr_date();
    292290
    293291        for( i = 0; i < tor->peerCount; )
     
    359357        while( ( p = blockPending( tor, peer, &size ) ) )
    360358        {
    361             if( !tr_uploadCanUpload( tor->upload ) )
     359            if( !tr_rcCanTransfer( tor->globalUpload ) )
    362360            {
    363361                break;
     
    375373
    376374            blockSent( peer, ret );
    377             tr_uploadUploaded( tor->upload, ret );
    378 
    379             tor->uploaded[9] += ret;
    380             peer->outTotal   += ret;
    381             peer->outDate     = tr_date();
     375            tr_rcTransferred( tor->upload, ret );
     376            tr_rcTransferred( tor->globalUpload, ret );
     377
     378            tor->uploaded  += ret;
     379            peer->outTotal += ret;
     380            peer->outDate   = tr_date();
    382381
    383382            /* In case this block is done, you may have messages
     
    459458    return peer->bitfield;
    460459}
     460
     461float tr_peerDownloadRate( tr_peer_t * peer )
     462{
     463    return tr_rcRate( peer->download );
     464}
     465
     466int tr_peerIsUnchoked( tr_peer_t * peer )
     467{
     468    return !peer->amChoking;
     469}
     470
     471int tr_peerIsInterested  ( tr_peer_t * peer )
     472{
     473    return peer->peerInterested;
     474}
     475
     476void tr_peerChoke( tr_peer_t * peer )
     477{
     478    sendChoke( peer, 1 );
     479    peer->lastChoke = tr_date();
     480}
     481
     482void tr_peerUnchoke( tr_peer_t * peer )
     483{
     484    sendChoke( peer, 0 );
     485    peer->lastChoke = tr_date();
     486}
     487
     488uint64_t tr_peerLastChoke( tr_peer_t * peer )
     489{
     490    return peer->lastChoke;
     491}
  • branches/oneport/libtransmission/peer.h

    r26 r69  
    3939int         tr_peerIsDownloading ( tr_peer_t * );
    4040uint8_t *   tr_peerBitfield      ( tr_peer_t * );
     41float       tr_peerDownloadRate  ( tr_peer_t * );
     42int         tr_peerIsUnchoked    ( tr_peer_t * );
     43int         tr_peerIsInterested  ( tr_peer_t * );
     44void        tr_peerChoke         ( tr_peer_t * );
     45void        tr_peerUnchoke       ( tr_peer_t * );
     46uint64_t    tr_peerLastChoke     ( tr_peer_t * );
    4147
    4248#endif
  • branches/oneport/libtransmission/peermessages.h

    r3 r69  
    6060        /* We need to load the block for the next request */
    6161        r = &peer->outRequests[0];
     62
     63        /* Sanity check */
     64        if( !tr_cpPieceIsComplete( tor->completion, r->index ) )
     65        {
     66            /* We have been asked for something we don't have, buggy client?
     67               Let's just drop this request */
     68            tr_inf( "Block %d/%d/%d was requested but we don't have it",
     69                    r->index, r->begin, r->length );
     70            (peer->outRequestCount)--;
     71            memmove( &peer->outRequests[0], &peer->outRequests[1],
     72                     peer->outRequestCount * sizeof( tr_request_t ) );
     73            return NULL;
     74        }
     75       
    6276        p = (uint8_t *) peer->outBlock;
    6377
  • branches/oneport/libtransmission/peerparse.h

    r30 r69  
    269269    }
    270270
     271    tor->downloaded += r->length;
     272
    271273    block = tr_block( r->index, r->begin );
    272274    if( tr_cpBlockIsComplete( tor->completion, block ) )
     
    439441}
    440442
    441 static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer,
    442                             int newBytes )
     443static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
    443444{
    444445    tr_info_t * inf = &tor->info;
     
    524525        }
    525526
    526         /* That's a piece coming */
    527         if( p < end && *p == 7 )
    528         {
    529             /* XXX */
    530             tor->downloaded[9] += newBytes;
    531             peer->inTotal      += newBytes;
    532             newBytes            = 0;
    533         }
    534 
    535527        if( &p[len] > end )
    536528        {
  • branches/oneport/libtransmission/peerutils.h

    r26 r69  
    3737    peer->date        = tr_date();
    3838    peer->keepAlive   = peer->date;
     39    peer->download    = tr_rcInit();
    3940
    4041    return peer;
     
    135136    }
    136137
    137     /* TODO: check for bad downloaders */
    138 
    139 #if 0
    140     /* Choke unchoked peers we are not sending anything to */
    141     if( !peer->amChoking && tr_date() > peer->outDate + 10000 )
    142     {
    143         peer_dbg( "not worth the unchoke" );
    144         if( sendChoke( peer, 1 ) )
    145         {
    146             goto dropPeer;
    147         }
    148         peer->outSlow = 1;
    149         tr_uploadChoked( tor->upload );
    150     }
    151 #endif
    152 
    153138    if( peer->status & PEER_STATUS_CONNECTED )
    154139    {
     
    158143            sendKeepAlive( peer );
    159144            peer->keepAlive = tr_date();
    160         }
    161 
    162         /* Choke or unchoke some people */
    163         /* TODO: prefer people who upload to us */
    164         if( !peer->amChoking && !peer->peerInterested )
    165         {
    166             /* He doesn't need us */
    167             sendChoke( peer, 1 );
    168             tr_uploadChoked( tor->upload );
    169         }
    170         if( peer->amChoking && peer->peerInterested &&
    171             !peer->outSlow && tr_uploadCanUnchoke( tor->upload ) )
    172         {
    173             sendChoke( peer, 0 );
    174             tr_uploadUnchoked( tor->upload );
    175145        }
    176146    }
  • branches/oneport/libtransmission/tracker.c

    r44 r69  
    283283            "Connection: close\r\n\r\n",
    284284            inf->trackerAnnounce, tor->hashString, tc->id,
    285             tc->bindPort, tor->uploaded[9], tor->downloaded[9],
     285            tc->bindPort, tor->uploaded, tor->downloaded,
    286286            left, tor->key, event, inf->trackerAddress,
    287287            VERSION_MAJOR, VERSION_MINOR );
  • branches/oneport/libtransmission/transmission.c

    r45 r69  
    2828static void torrentReallyStop( tr_handle_t * h, int t );
    2929static void  downloadLoop( void * );
    30 static float rateDownload( tr_torrent_t * );
    31 static float rateUpload( tr_torrent_t * );
    3230static void  acceptLoop( void * );
    3331static void acceptStop( tr_handle_t * h );
     
    6664
    6765    /* Initialize rate and file descripts controls */
    68     h->upload  = tr_uploadInit();
    69     h->fdlimit = tr_fdInit();
     66    h->upload   = tr_rcInit();
     67    h->download = tr_rcInit();
     68    h->fdlimit  = tr_fdInit();
     69    h->choking  = tr_chokingInit( h );
    7070
    7171    h->bindPort = TR_DEFAULT_PORT;
     
    146146void tr_setUploadLimit( tr_handle_t * h, int limit )
    147147{
    148     tr_uploadSetLimit( h->upload, limit );
     148    tr_rcSetLimit( h->upload, limit );
     149    tr_chokingSetLimit( h->choking, limit );
    149150}
    150151
     
    156157void tr_torrentRates( tr_handle_t * h, float * dl, float * ul )
    157158{
    158     int            i;
    159     tr_torrent_t * tor;
    160 
    161     *dl = 0.0;
    162     *ul = 0.0;
    163 
    164     for( i = 0; i < h->torrentCount; i++ )
    165     {
    166         tor = h->torrents[i];
    167         tr_lockLock( &tor->lock );
    168         *dl += rateDownload( tor );
    169         *ul += rateUpload( tor );
    170         tr_lockUnlock( &tor->lock );
    171     }
     159    *dl = tr_rcRate( h->download );
     160    *ul = tr_rcRate( h->upload );
    172161}
    173162
     
    249238    tr_lockInit( &tor->lock );
    250239
    251     tor->upload  = h->upload;
    252     tor->fdlimit = h->fdlimit;
     240    tor->globalUpload   = h->upload;
     241    tor->globalDownload = h->download;
     242    tor->fdlimit        = h->fdlimit;
     243    tor->upload         = tr_rcInit();
     244    tor->download       = tr_rcInit();
    253245 
    254246    /* We have a new torrent */
     
    289281{
    290282    tr_torrent_t * tor = h->torrents[t];
    291     uint64_t       now;
    292     int            i;
    293283
    294284    if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
     
    301291    tor->tracker  = tr_trackerInit( h, tor );
    302292
    303     now = tr_date();
    304     for( i = 0; i < 10; i++ )
    305     {
    306         tor->dates[i] = now;
    307     }
    308 
     293    tor->date = tr_date();
    309294    tor->die = 0;
    310295    tr_threadCreate( &tor->thread, downloadLoop, tor );
     
    341326        tr_peerRem( tor, 0 );
    342327    }
     328
     329    tor->downloaded = 0;
     330    tor->uploaded   = 0;
    343331}
    344332
     
    417405
    418406        s[i].progress     = tr_cpCompletionAsFloat( tor->completion );
    419         s[i].rateDownload = rateDownload( tor );
    420         s[i].rateUpload   = rateUpload( tor );
     407        s[i].rateDownload = tr_rcRate( tor->download );
     408        s[i].rateUpload   = tr_rcRate( tor->upload );
    421409       
    422410        s[i].seeders      = tr_trackerSeeders(tor);
     
    459447        }
    460448
    461         s[i].downloaded = tor->downloaded[9];
    462         s[i].uploaded   = tor->uploaded[9];
     449        s[i].downloaded = tor->downloaded;
     450        s[i].uploaded   = tor->uploaded;
    463451
    464452        s[i].folder = tor->destination;
     
    493481    tr_lockClose( &tor->lock );
    494482    tr_cpClose( tor->completion );
     483
     484    tr_rcClose( tor->upload );
     485    tr_rcClose( tor->download );
    495486
    496487    if( tor->destination )
     
    511502{
    512503    acceptStop( h );
     504    tr_chokingClose( h->choking );
    513505    tr_fdClose( h->fdlimit );
    514     tr_uploadClose( h->upload );
     506    tr_rcClose( h->upload );
     507    tr_rcClose( h->download );
    515508    free( h );
    516509}
     
    584577
    585578/***********************************************************************
    586  * rateDownload, rateUpload
    587  **********************************************************************/
    588 static float rateGeneric( uint64_t * dates, uint64_t * counts )
    589 {
    590     float ret;
    591     int i;
    592 
    593     ret = 0.0;
    594     for( i = 0; i < 9; i++ )
    595     {
    596         if( dates[i+1] == dates[i] )
    597         {
    598             continue;
    599         }
    600         ret += (float) ( i + 1 ) * 1000.0 / 1024.0 *
    601             (float) ( counts[i+1] - counts[i] ) /
    602             (float) ( dates[i+1] - dates[i] );
    603     }
    604     ret *= 1000.0 / 1024.0 / 45.0;
    605 
    606     return ret;
    607 }
    608 static float rateDownload( tr_torrent_t * tor )
    609 {
    610     if( TR_STATUS_PAUSE & tor->status )
    611     {
    612         return 0.0;
    613     }
    614     return rateGeneric( tor->dates, tor->downloaded );
    615 }
    616 static float rateUpload( tr_torrent_t * tor )
    617 {
    618     if( TR_STATUS_PAUSE & tor->status )
    619     {
    620         return 0.0;
    621     }
    622     return rateGeneric( tor->dates, tor->uploaded );
    623 }
    624 
    625 /***********************************************************************
    626579 * acceptLoop
    627580 **********************************************************************/
     
    629582{
    630583    tr_handle_t * h = _h;
    631     uint64_t      date1, date2;
     584    uint64_t      date1, date2, lastchoke = 0;
    632585    int           ii, jj;
    633586    uint8_t     * hash;
     
    698651        }
    699652
     653        if( date1 > lastchoke + 2000 )
     654        {
     655            tr_chokingPulse( h->choking );
     656            lastchoke = date1;
     657        }
     658
    700659        /* Wait up to 20 ms */
    701660        date2 = tr_date();
  • branches/oneport/macosx/Controller.h

    r19 r69  
    2424#define CONTROLLER_H
    2525
    26 #include <Cocoa/Cocoa.h>
    27 #include <transmission.h>
    28 #include "PrefsController.h"
     26#import <Cocoa/Cocoa.h>
     27#import <transmission.h>
     28#import "PrefsController.h"
     29#import "Badger.h"
    2930
    3031@class TorrentTableView;
     
    3334{
    3435    tr_handle_t                 * fHandle;
    35     int                         fCount;
     36    int                         fCount, fSeeding, fDownloading, fCompleted;
    3637    tr_stat_t                   * fStat;
    3738    int                         fResumeOnWake[TR_MAX_TORRENT_COUNT];
     
    6970    NSArray                     * fFilenames;
    7071    NSTimer                     * fTimer;
     72    NSTimer                     * fUpdateTimer;
    7173   
    7274    IBOutlet NSPanel            * fPrefsWindow;
     
    7577   
    7678    BOOL                        fHasGrowl;
     79    Badger                      * fBadger;
     80    BOOL                        fCheckIsAutomatic;
    7781}
    7882
     
    8488- (void) quitSheetDidEnd:   (NSWindow *)sheet returnCode:(int)returnCode
    8589                            contextInfo:(void  *)contextInfo;
    86 - (void) quitProcedure;
    8790                       
    8891- (void) stopTorrent:               (id) sender;
     
    127130- (void) growlRegister:     (id) sender;
    128131
     132- (void) checkForUpdate:      (id) sender;
     133- (void) checkForUpdateTimer: (NSTimer *) timer;
     134- (void) checkForUpdateAuto:  (BOOL) automatic;
     135
    129136@end
    130137
  • branches/oneport/macosx/Controller.m

    r29 r69  
    2121 *****************************************************************************/
    2222
    23 #include <IOKit/IOMessage.h>
    24 
    25 #include "NameCell.h"
    26 #include "ProgressCell.h"
    27 #include "Utils.h"
    28 #include "TorrentTableView.h"
     23#import <IOKit/IOMessage.h>
     24
     25#import "NameCell.h"
     26#import "ProgressCell.h"
     27#import "StringAdditions.h"
     28#import "Utils.h"
     29#import "TorrentTableView.h"
    2930
    3031#import "PrefsController.h"
     
    3637#define TOOLBAR_RESUME_ALL  @"Toolbar Resume All"
    3738
    38 #define WEBSITE_URL     @"http://transmission.m0k.org/"
    39 #define FORUM_URL       @"http://transmission.m0k.org/forum/"
     39#define WEBSITE_URL         @"http://transmission.m0k.org/"
     40#define FORUM_URL           @"http://transmission.m0k.org/forum/"
     41#define VERSION_PLIST_URL   @"http://transmission.m0k.org/version.plist"
    4042
    4143#define GROWL_PATH  @"/Library/PreferencePanes/Growl.prefPane/Contents/Resources/GrowlHelperApp.app"
     
    133135                GROWL_PATH] stringByExpandingTildeInPath]];
    134136    [self growlRegister: self];
     137
     138    //initialize badging
     139    fBadger = [[Badger alloc] init];
    135140   
    136141    //update the interface every 500 ms
    137142    fCount = 0;
    138     fStat  = NULL;
     143    fDownloading = 0;
     144    fSeeding = 0;
     145    fCompleted = 0;
     146    fStat  = nil;
    139147    fTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5 target: self
    140148        selector: @selector( updateUI: ) userInfo: NULL repeats: YES];
    141149    [[NSRunLoop currentRunLoop] addTimer: fTimer
     150        forMode: NSModalPanelRunLoopMode];
     151    [[NSRunLoop currentRunLoop] addTimer: fTimer
    142152        forMode: NSEventTrackingRunLoopMode];
     153
     154    [self checkForUpdateTimer: nil];
     155    fUpdateTimer = [NSTimer scheduledTimerWithTimeInterval: 60.0
     156        target: self selector: @selector( checkForUpdateTimer: )
     157        userInfo: NULL repeats: YES];
     158}
     159
     160- (void) windowDidBecomeKey: (NSNotification *) n
     161{
     162    /* Reset the number of recently completed downloads */
     163    fCompleted = 0;
    143164}
    144165
     
    163184- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
    164185{
    165     if ([[fDefaults stringForKey: @"CheckQuit"] isEqualToString:@"YES"])
    166     {
    167         int i;
    168         for( i = 0; i < fCount; i++ )
    169         {
    170             if( fStat[i].status & ( TR_STATUS_CHECK |
    171                     TR_STATUS_DOWNLOAD ) )
    172             {
    173                 NSBeginAlertSheet(@"Confirm Quit",
    174                                 @"Quit", @"Cancel", nil,
    175                                 fWindow, self,
    176                                 @selector(quitSheetDidEnd:returnCode:contextInfo:),
    177                                 NULL, NULL, @"There are active torrents. Do you really want to quit?");
    178                 return NSTerminateLater;
    179             }
    180         }
    181     }
    182    
    183     [self quitProcedure];
     186    int active = fDownloading + fSeeding;
     187    if (active > 0 && [[NSUserDefaults standardUserDefaults] boolForKey: @"CheckQuit"])
     188    {
     189        NSString * message = active == 1
     190            ? @"There is an active torrent. Do you really want to quit?"
     191            : [NSString stringWithFormat:
     192                @"There are %d active torrents. Do you really want to quit?", fDownloading];
     193
     194        NSBeginAlertSheet(@"Confirm Quit",
     195                            @"Quit", @"Cancel", nil,
     196                            fWindow, self,
     197                            @selector(quitSheetDidEnd:returnCode:contextInfo:),
     198                            nil, nil, message);
     199        return NSTerminateLater;
     200    }                                                                           
     201   
    184202    return NSTerminateNow;
    185203}
     
    188206                        contextInfo:(void  *)contextInfo
    189207{
    190     if (returnCode == NSAlertDefaultReturn)
    191         [self quitProcedure];
    192        
    193208    [NSApp stopModal];
    194     [NSApp replyToApplicationShouldTerminate: (returnCode == NSAlertDefaultReturn)];
    195 }
    196 
    197 - (void) quitProcedure
     209    [NSApp replyToApplicationShouldTerminate:
     210        (returnCode == NSAlertDefaultReturn)];
     211}
     212
     213- (void) applicationWillTerminate: (NSNotification *) notification
    198214{
    199215    int i;
    200     NSMutableArray * history = [NSMutableArray
    201         arrayWithCapacity: TR_MAX_TORRENT_COUNT];
    202216   
    203217    // Stop updating the interface
    204218    [fTimer invalidate];
     219    [fUpdateTimer invalidate];
     220
     221    //clear badge
     222    [fBadger clearBadge];
     223    [fBadger release];                                                         
    205224
    206225    // Save history and stop running torrents
     226    NSMutableArray * history = [NSMutableArray arrayWithCapacity: fCount];
     227    BOOL active;
    207228    for( i = 0; i < fCount; i++ )
    208229    {
     230        active = fStat[i].status &
     231            ( TR_STATUS_CHECK | TR_STATUS_DOWNLOAD | TR_STATUS_SEED );
     232
    209233        [history addObject: [NSDictionary dictionaryWithObjectsAndKeys:
    210234            [NSString stringWithUTF8String: fStat[i].info.torrent],
     
    212236            [NSString stringWithUTF8String: tr_torrentGetFolder( fHandle, i )],
    213237            @"DownloadFolder",
    214             ( fStat[i].status & ( TR_STATUS_CHECK | TR_STATUS_DOWNLOAD |
    215                 TR_STATUS_SEED ) ) ? @"NO" : @"YES",
     238            active ? @"NO" : @"YES",
    216239            @"Paused",
    217240            NULL]];
    218241
    219         if( fStat[i].status & ( TR_STATUS_CHECK |
    220                 TR_STATUS_DOWNLOAD | TR_STATUS_SEED ) )
     242        if( active )
    221243        {
    222244            tr_torrentStop( fHandle, i );
    223245        }
    224246    }
     247    [fDefaults setObject: history forKey: @"History"];
    225248
    226249    // Wait for torrents to stop (5 seconds timeout)
     
    228251    while( fCount > 0 )
    229252    {
    230         while( [[NSDate date] timeIntervalSinceDate: start] < 5 )
    231         {
    232             fCount = tr_torrentStat( fHandle, &fStat );
    233             if( fStat[0].status & TR_STATUS_PAUSE )
    234             {
    235                 break;
    236             }
    237             usleep( 500000 );
     253        while( [[NSDate date] timeIntervalSinceDate: start] < 5 &&
     254                !( fStat[0].status & TR_STATUS_PAUSE ) )
     255        {
     256            usleep( 100000 );
     257            tr_torrentStat( fHandle, &fStat );
    238258        }
    239259        tr_torrentClose( fHandle, 0 );
     
    242262
    243263    tr_close( fHandle );
    244 
    245     [fDefaults setObject: history forKey: @"History"];
    246264}
    247265
     
    303321        {
    304322            tr_torrentSetFolder( fHandle, tr_torrentCount( fHandle ) - 1,
    305                                  [downloadFolder UTF8String] );
     323                                 [[downloadFolder stringByExpandingTildeInPath] UTF8String] );
    306324            tr_torrentStart( fHandle, tr_torrentCount( fHandle ) - 1 );
    307325        }
     
    443461{
    444462    if ( fStat[idx].status & ( TR_STATUS_CHECK
    445         | TR_STATUS_DOWNLOAD)  )
    446     {
    447         if ([[fDefaults stringForKey: @"CheckRemove"] isEqualToString:@"YES"])
     463        | TR_STATUS_DOWNLOAD | TR_STATUS_SEED )  )
     464    {
     465        if ([fDefaults boolForKey: @"CheckRemove"])
    448466        {
    449467            NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
     
    553571       
    554572    fCount = tr_torrentStat( fHandle, &fStat );
     573    fDownloading = 0;
     574    fSeeding = 0;
    555575    [fTableView updateUI: fStat];
    556576
    557577    //Update the global DL/UL rates
    558578    tr_torrentRates( fHandle, &dl, &ul );
    559     [fTotalDLField setStringValue: [NSString stringWithFormat:
    560         @"Total DL: %.2f KB/s", dl]];
    561     [fTotalULField setStringValue: [NSString stringWithFormat:
    562         @"Total UL: %.2f KB/s", ul]];
     579    NSString * downloadRate = [NSString stringForSpeed: dl];
     580    NSString * uploadRate = [NSString stringForSpeed: ul];
     581    [fTotalDLField setStringValue: downloadRate];
     582    [fTotalULField setStringValue: uploadRate];
    563583
    564584    //Update DL/UL totals in the Info panel
     
    567587    {
    568588        [fInfoDownloaded setStringValue:
    569             stringForFileSize( fStat[row].downloaded )];
     589            [NSString stringForFileSize: fStat[row].downloaded]];
    570590        [fInfoUploaded setStringValue:
    571             stringForFileSize( fStat[row].uploaded )];
     591            [NSString stringForFileSize: fStat[row].uploaded]];
    572592    }
    573593   
     
    575595    for (i = 0; i < fCount; i++)
    576596    {
     597        if (fStat[i].status & (TR_STATUS_CHECK | TR_STATUS_DOWNLOAD))
     598            fDownloading++;
     599        else if (fStat[i].status & TR_STATUS_SEED)
     600            fSeeding++;
     601
    577602        if( !tr_getFinished( fHandle, i ) )
    578603            continue;
    579            
     604
     605        fCompleted++;
    580606        [self notifyGrowl: [NSString stringWithUTF8String:
    581607            fStat[i].info.name]];
    582608        tr_setFinished( fHandle, i, 0 );
    583609    }
     610
     611    //badge dock
     612    NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
     613    [fBadger updateBadgeWithCompleted: [defaults boolForKey: @"BadgeCompleted"] ? fCompleted : 0
     614                    uploadRate: ul >= 0.1 && [defaults boolForKey: @"BadgeUploadRate"] ? uploadRate : nil
     615                    downloadRate: dl >= 0.1 && [defaults boolForKey: @"BadgeDownloadRate"] ? downloadRate : nil];
    584616}
    585617
     
    664696        fStat[row].info.trackerAnnounce]];
    665697    [fInfoSize setStringValue:
    666         stringForFileSize( fStat[row].info.totalSize )];
     698        [NSString stringForFileSize: fStat[row].info.totalSize]];
    667699    [fInfoPieces setStringValue: [NSString stringWithFormat: @"%d",
    668700        fStat[row].info.pieceCount]];
    669701    [fInfoPieceSize setStringValue:
    670         stringForFileSize( fStat[row].info.pieceSize )];
     702        [NSString stringForFileSize: fStat[row].info.pieceSize]];
    671703    [fInfoFolder setStringValue: [[NSString stringWithUTF8String:
    672704        tr_torrentGetFolder( fHandle, row )] lastPathComponent]];
     
    723755        [item setPaletteLabel: [item label]];
    724756        [item setToolTip: @"Resume all torrents"];
    725         [item setImage: [NSImage imageNamed: @"Resume.png"]];
     757        [item setImage: [NSImage imageNamed: @"ResumeAll.png"]];
    726758        [item setTarget: self];
    727759        [item setAction: @selector( resumeAllTorrents: )];
     
    732764        [item setPaletteLabel: [item label]];
    733765        [item setToolTip: @"Pause all torrents"];
    734         [item setImage: [NSImage imageNamed: @"Stop.png"]];
     766        [item setImage: [NSImage imageNamed: @"PauseAll.png"]];
    735767        [item setTarget: self];
    736768        [item setAction: @selector( stopAllTorrents: )];
     
    781813- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
    782814{
     815    SEL action = [toolbarItem action];
     816
    783817    //enable remove item
    784     if ([toolbarItem action] == @selector(removeTorrent:))
     818    if (action == @selector(removeTorrent:))
    785819        return [fTableView selectedRow] >= 0;
    786820       
    787     //enable pause all and resume all items
    788     if ([toolbarItem action] == @selector(stopAllTorrents:)
    789             || [toolbarItem action] == @selector(resumeAllTorrents:))
    790         return fCount > 0;
     821
     822    //enable resume all item
     823    if (action == @selector(resumeAllTorrents:))
     824        return fCount > fDownloading + fSeeding;
     825
     826    //enable pause all item
     827    if (action == @selector(stopAllTorrents:))
     828        return fDownloading > 0 || fSeeding > 0;                               
    791829   
    792830    return YES;
     
    795833- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
    796834{
     835    SEL action = [menuItem action];
     836
    797837    //disable menus if customize sheet is active
    798838    if ([fToolbar customizationPaletteIsRunning])
     
    800840       
    801841    //enable customize toolbar item
    802     if ([menuItem action] == @selector(showHideToolbar:))
     842    if (action == @selector(showHideToolbar:))
    803843    {
    804844        [menuItem setTitle: [fToolbar isVisible] ? @"Hide Toolbar" : @"Show Toolbar"];
     
    807847       
    808848    //enable show info
    809     if ([menuItem action] == @selector(showInfo:))
     849    if (action == @selector(showInfo:))
    810850    {
    811851        [menuItem setTitle: [fInfoPanel isVisible] ? @"Hide Info" : @"Show Info"];
    812852        return YES;
    813853    }
    814    
    815     //enable pause all and resume all
    816     if ([menuItem action] == @selector(stopAllTorrents:) || [menuItem action] == @selector(resumeAllTorrents:))
    817         return fCount > 0;
    818        
     854
     855    //enable resume all item
     856    if (action == @selector(resumeAllTorrents:))
     857        return fCount > fDownloading + fSeeding;
     858
     859    //enable pause all item
     860    if (action == @selector(stopAllTorrents:))
     861        return fDownloading > 0 || fSeeding > 0;                               
     862   
    819863    int row = [fTableView selectedRow];
    820864       
    821865    //enable remove items
    822     if ([menuItem action] == @selector(removeTorrent:)
    823         || [menuItem action] == @selector(removeTorrentDeleteFile:)
    824         || [menuItem action] == @selector(removeTorrentDeleteData:)
    825         || [menuItem action] == @selector(removeTorrentDeleteBoth:))
     866    if (action == @selector(removeTorrent:)
     867        || action == @selector(removeTorrentDeleteFile:)
     868        || action == @selector(removeTorrentDeleteData:)
     869        || action == @selector(removeTorrentDeleteBoth:))
    826870    {
    827871        //append or remove ellipsis when needed
     
    841885   
    842886    //enable reveal in finder item
    843     if ([menuItem action] == @selector(revealFromMenu:))
     887    if (action == @selector(revealFromMenu:))
    844888        return row >= 0;
    845889       
    846890    //enable and change pause / remove item
    847     if ([menuItem action] == @selector(resumeTorrent:) || [menuItem action] == @selector(stopTorrent:))
     891    if (action == @selector(resumeTorrent:) || action == @selector(stopTorrent:))
    848892    {
    849893        if (row >= 0 && fStat[row].status & TR_STATUS_PAUSE)
     
    894938
    895939        case kIOMessageCanSystemSleep:
    896             /* Do not prevent idle sleep */
    897             /* TODO: prevent it unless there are all paused? */
    898             IOAllowPowerChange( fRootPort, (long) messageArgument );
     940            /* Prevent idle sleep unless all paused */
     941            if (fDownloading > 0 || fSeeding > 0)
     942                IOCancelPowerChange( fRootPort, (long) messageArgument );
     943            else
     944                IOAllowPowerChange( fRootPort, (long) messageArgument );
    899945            break;
    900946
     
    10531099}
    10541100
     1101- (void) checkForUpdate: (id) sender
     1102{
     1103    [self checkForUpdateAuto: NO];
     1104}
     1105
     1106- (void) checkForUpdateTimer: (NSTimer *) timer
     1107{
     1108    NSString * check = [fDefaults stringForKey: @"VersionCheck"];
     1109    if( [check isEqualToString: @"Never"] )
     1110        return;
     1111
     1112    NSTimeInterval interval;
     1113    if( [check isEqualToString: @"Daily"] )
     1114        interval = 24 * 3600;
     1115    else if( [check isEqualToString: @"Weekly"] )
     1116        interval = 7 * 24 * 3600;
     1117    else
     1118        return;
     1119
     1120    id lastObject = [fDefaults objectForKey: @"VersionCheckLast"];
     1121    NSDate * lastDate = [lastObject isKindOfClass: [NSDate class]] ?
     1122        lastObject : nil;
     1123    if( lastDate )
     1124    {
     1125        NSTimeInterval actualInterval =
     1126            [[NSDate date] timeIntervalSinceDate: lastDate];
     1127        if( actualInterval > 0 && actualInterval < interval )
     1128        {
     1129            return;
     1130        }
     1131    }
     1132
     1133    [self checkForUpdateAuto: YES];
     1134    [fDefaults setObject: [NSDate date] forKey: @"VersionCheckLast"];
     1135}
     1136   
     1137- (void) checkForUpdateAuto: (BOOL) automatic
     1138{
     1139    fCheckIsAutomatic = automatic;
     1140    [[NSURL URLWithString: VERSION_PLIST_URL]
     1141            loadResourceDataNotifyingClient: self usingCache: NO];
     1142}
     1143
     1144- (void) URLResourceDidFinishLoading: (NSURL *) sender
     1145{   
     1146    NSDictionary * dict = [NSPropertyListSerialization
     1147                            propertyListFromData: [sender resourceDataUsingCache: NO]
     1148                            mutabilityOption: NSPropertyListImmutable
     1149                            format: nil errorDescription: nil];
     1150
     1151    //check if plist was actually found and contains a version
     1152    NSString * webVersion = nil;
     1153    if (dict)
     1154        webVersion = [dict objectForKey: @"Version"];
     1155    if (!webVersion)
     1156    {
     1157        if (!fCheckIsAutomatic)
     1158        {
     1159            NSAlert * dialog = [[NSAlert alloc] init];
     1160            [dialog addButtonWithTitle: @"OK"];
     1161            [dialog setMessageText: @"Error checking for updates."];
     1162            [dialog setInformativeText:
     1163                    @"Transmission was not able to check the latest version available."];
     1164            [dialog setAlertStyle: NSInformationalAlertStyle];
     1165
     1166            [dialog runModal];
     1167            [dialog release];
     1168        }
     1169        return;
     1170    }
     1171
     1172    NSString * currentVersion = [[[NSBundle mainBundle] infoDictionary]
     1173                                objectForKey: (NSString *)kCFBundleVersionKey];
     1174
     1175    NSEnumerator * webEnum = [[webVersion componentsSeparatedByString: @"."] objectEnumerator],
     1176            * currentEnum = [[currentVersion componentsSeparatedByString: @"."] objectEnumerator];
     1177    NSString * webSub, * currentSub;
     1178
     1179    BOOL webGreater = NO;
     1180    NSComparisonResult result;
     1181    while ((webSub = [webEnum nextObject]))
     1182    {
     1183        if (!(currentSub = [currentEnum nextObject]))
     1184        {
     1185            webGreater = YES;
     1186            break;
     1187        }
     1188
     1189        result = [currentSub compare: webSub options: NSNumericSearch];
     1190        if (result != NSOrderedSame)
     1191        {
     1192            if (result == NSOrderedAscending)
     1193                webGreater = YES;
     1194            break;
     1195        }
     1196    }
     1197
     1198    if (webGreater)
     1199    {
     1200        NSAlert * dialog = [[NSAlert alloc] init];
     1201        [dialog addButtonWithTitle: @"Go to Website"];
     1202        [dialog addButtonWithTitle:@"Cancel"];
     1203        [dialog setMessageText: @"New version is available!"];
     1204        [dialog setInformativeText: [NSString stringWithFormat:
     1205            @"A newer version (%@) is available for download from the Transmission website.", webVersion]];
     1206        [dialog setAlertStyle: NSInformationalAlertStyle];
     1207
     1208        if ([dialog runModal] == NSAlertFirstButtonReturn)
     1209            [self linkHomepage: nil];
     1210
     1211        [dialog release];
     1212    }
     1213    else if (!fCheckIsAutomatic)
     1214    {
     1215        NSAlert * dialog = [[NSAlert alloc] init];
     1216        [dialog addButtonWithTitle: @"OK"];
     1217        [dialog setMessageText: @"No new versions are available."];
     1218        [dialog setInformativeText: [NSString stringWithFormat:
     1219            @"You are running the most current version of Transmission (%@).", currentVersion]];
     1220        [dialog setAlertStyle: NSInformationalAlertStyle];
     1221
     1222        [dialog runModal];
     1223        [dialog release];
     1224    }
     1225    else;
     1226}
     1227
    10551228@end
  • branches/oneport/macosx/Defaults.plist

    r38 r69  
    3535        <key>UseAdvancedBar</key>
    3636        <false/>
    37         <key>VersionStartupCheck</key>
    38         <true/>
     37        <key>VersionCheck</key>
     38        <string>Weekly</string>
    3939</dict>
    4040</plist>
  • branches/oneport/macosx/English.lproj/MainMenu.nib/classes.nib

    r20 r69  
    44            ACTIONS = {
    55                advancedChanged = id;
     6                checkForUpdate = id;
    67                growlRegister = id;
    78                linkForums = id;
     
    6061            ACTIONS = {
    6162                folderSheetShow = id;
     63                setBadge = id;
    6264                setDownloadLocation = id;
    6365                setLimitUploadCheck = id;
     
    6567                setQuitMessage = id;
    6668                setRemoveMessage = id;
     69                setUpdate = id;
    6770                setUploadLimit = id;
    6871            };
     
    7073            LANGUAGE = ObjC;
    7174            OUTLETS = {
     75                fBadgeCompletedCheck = NSButton;
     76                fBadgeDownloadRateCheck = NSButton;
     77                fBadgeUploadRateCheck = NSButton;
    7278                fBlankView = NSView;
    7379                fFolderPopUp = NSPopUpButton;
     
    7884                fQuitCheck = NSButton;
    7985                fRemoveCheck = NSButton;
     86                fUpdatePopUp = NSPopUpButton;
    8087                fUploadCheck = NSButton;
    8188                fUploadField = NSTextField;
  • branches/oneport/macosx/English.lproj/MainMenu.nib/info.nib

    r20 r69  
    44<dict>
    55        <key>IBDocumentLocation</key>
    6         <string>62 66 426 365 0 0 1280 832 </string>
     6        <string>62 69 426 365 0 0 1280 832 </string>
    77        <key>IBEditorPositions</key>
    88        <dict>
     
    1616                <string>54 521 112 118 0 0 1152 842 </string>
    1717                <key>783</key>
    18                 <string>409 477 420 155 0 0 1280 832 </string>
     18                <string>387 422 470 265 0 0 1280 832 </string>
    1919                <key>796</key>
    20                 <string>409 490 420 129 0 0 1280 832 </string>
     20                <string>412 490 470 129 0 0 1280 832 </string>
    2121                <key>825</key>
    22                 <string>542 501 155 107 0 0 1280 832 </string>
     22                <string>544 501 155 107 0 0 1280 832 </string>
    2323        </dict>
    2424        <key>IBFramework Version</key>
     
    2828        <key>IBOpenObjects</key>
    2929        <array>
    30                 <integer>781</integer>
    3130                <integer>783</integer>
    32                 <integer>21</integer>
    33                 <integer>796</integer>
    34                 <integer>825</integer>
    35                 <integer>29</integer>
    3631        </array>
    3732        <key>IBSystem Version</key>
    38         <string>8F46</string>
     33        <string>8G32</string>
    3934</dict>
    4035</plist>
  • branches/oneport/macosx/NameCell.h

    r15 r69  
    2424#define NAMECELL_H
    2525
    26 #include <Cocoa/Cocoa.h>
    27 #include <transmission.h>
    28 #include "Controller.h"
     26#import <Cocoa/Cocoa.h>
     27#import <transmission.h>
     28#import "Controller.h"
    2929
    3030@interface NameCell : NSCell
     
    3636    NSString * fTimeString;
    3737    NSString * fPeersString;
     38
     39    NSImage * fIcon;
    3840}
    3941- (void) setStat: (tr_stat_t *) stat whiteText: (BOOL) w;
  • branches/oneport/macosx/NameCell.m

    r15 r69  
    2121 *****************************************************************************/
    2222
    23 #include "NameCell.h"
    24 #include "Utils.h"
     23#import "NameCell.h"
     24#import "StringAdditions.h"
     25#import "Utils.h"
    2526
    2627@implementation NameCell
     
    3233    fNameString  = [NSString stringWithUTF8String: stat->info.name];
    3334    fSizeString  = [NSString stringWithFormat: @" (%@)",
    34                     stringForFileSize( stat->info.totalSize )];
     35                    [NSString stringForFileSize: stat->info.totalSize]];
     36
     37    fIcon = [[NSWorkspace sharedWorkspace] iconForFile:
     38                [[NSString stringWithUTF8String: stat->folder]
     39                stringByAppendingPathComponent: fNameString]];                 
     40    [fIcon setFlipped: YES];
     41
    3542    fTimeString  = @"";
    3643    fPeersString = @"";
     
    97104
    98105    pen = cellFrame.origin;
     106    float cellWidth = cellFrame.size.width;
     107
     108    pen.x += 5;
     109    pen.y += 5;                                                                 
     110    [fIcon drawAtPoint: pen fromRect:
     111        NSMakeRect(0,0,[fIcon size].width,[fIcon size].height)
     112        operation: NSCompositeSourceOver fraction: 1.0];
    99113
    100114    attributes = [NSMutableDictionary dictionaryWithCapacity: 2];
     
    105119        forKey: NSFontAttributeName];
    106120
    107     pen.x += 5; pen.y += 5;
    108     string = [NSString stringWithFormat: @"%@%@",
    109         stringFittingInWidth( fNameString, cellFrame.size.width -
    110         35 - widthForString( fSizeString, 12 ), 12 ), fSizeString];
     121    pen.x += 37;
     122    string = [[fNameString stringFittingInWidth: cellWidth -
     123        72 - [fSizeString sizeWithAttributes: attributes].width
     124        withAttributes: attributes] stringByAppendingString: fSizeString];
    111125    [string drawAtPoint: pen withAttributes: attributes];
    112126
     
    118132
    119133    pen.x += 0; pen.y += 15;
    120     string = stringFittingInWidth( fPeersString,
    121                 cellFrame.size.width - 40, 10 );
     134    string = [fPeersString stringFittingInWidth: cellFrame.size.width -
     135        77 withAttributes: attributes];
    122136    [string drawAtPoint: pen withAttributes: attributes];
    123137
  • branches/oneport/macosx/PrefsController.h

    r20 r69  
    2121 *****************************************************************************/
    2222
    23 #include <Cocoa/Cocoa.h>
    24 #include <transmission.h>
     23#import <Cocoa/Cocoa.h>
     24#import <transmission.h>
    2525
    2626@interface PrefsController : NSObject
     
    3636   
    3737    IBOutlet NSPopUpButton  * fFolderPopUp;
     38    IBOutlet NSButton       * fQuitCheck;
     39    IBOutlet NSButton       * fRemoveCheck;
     40    IBOutlet NSButton       * fBadgeCompletedCheck;
     41    IBOutlet NSButton       * fBadgeDownloadRateCheck;
     42    IBOutlet NSButton       * fBadgeUploadRateCheck;                           
     43    IBOutlet NSPopUpButton  * fUpdatePopUp;
     44
    3845    IBOutlet NSTextField    * fPortField;
    3946    IBOutlet NSButton       * fUploadCheck;
    4047    IBOutlet NSTextField    * fUploadField;
    41     IBOutlet NSButton       * fQuitCheck;
    42     IBOutlet NSButton       * fRemoveCheck;
    4348   
    4449    IBOutlet NSWindow       * fWindow;
     
    5055- (void) setPrefsWindow: (tr_handle_t *) handle;
    5156
     57- (void) setQuitMessage:        (id) sender;
     58- (void) setRemoveMessage:      (id) sender;
     59- (void) setBadge:              (id) sender;
     60- (void) setUpdate:             (id) sender;
     61- (void) setDownloadLocation:   (id) sender;
     62- (void) folderSheetShow:       (id) sender;
     63
    5264- (void) setLimitUploadCheck:   (id) sender;
    5365- (void) setPort:               (id) sender;
    5466- (void) setUploadLimit:        (id) sender;
    55 - (void) setQuitMessage:        (id) sender;
    56 - (void) setRemoveMessage:  (id) sender;
    57 - (void) setDownloadLocation:   (id) sender;
    58 - (void) folderSheetShow:       (id) sender;
    5967
    6068@end
  • branches/oneport/macosx/PrefsController.m

    r20 r69  
    2121 *****************************************************************************/
    2222
    23 #include "PrefsController.h"
    24 
    25 #define DEFAULT_UPLOAD      @"20"
     23#import "PrefsController.h"
     24
    2625#define MIN_PORT            1
    2726#define MAX_PORT            65535
     
    3130#define DOWNLOAD_ASK        3
    3231
     32#define UPDATE_DAILY        0
     33#define UPDATE_WEEKLY       1
     34#define UPDATE_NEVER        2
     35
    3336#define TOOLBAR_GENERAL     @"General"
    3437#define TOOLBAR_NETWORK     @"Network"
     
    5154+ (void) initialize
    5255{
    53     NSDictionary   * appDefaults;
    54     NSString       * desktop, * port;
    55 
    56     /* Register defaults settings:
    57         - Simple bar
    58         - Always download to Desktop
    59         - Port TR_DEFAULT_PORT
    60         - Upload limit DEFAULT_UPLOAD
    61         - Limit upload
    62         - Ask before quitting
    63         - Ask before removing */
    64     desktop = [NSHomeDirectory() stringByAppendingString: @"/Desktop"];
    65     port = [NSString stringWithFormat: @"%d", TR_DEFAULT_PORT];
    66 
    67     appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
    68                     @"NO",          @"UseAdvancedBar",
    69                     @"Constant",    @"DownloadChoice",
    70                     desktop,        @"DownloadFolder",
    71                     port,           @"BindPort",
    72                     DEFAULT_UPLOAD, @"UploadLimit",
    73                     @"YES",         @"CheckUpload",
    74                     @"YES",         @"CheckQuit",
    75                     @"YES",         @"CheckRemove",
    76                     NULL];
    77     [[NSUserDefaults standardUserDefaults] registerDefaults: appDefaults];
     56    [[NSUserDefaults standardUserDefaults] registerDefaults:
     57        [NSDictionary dictionaryWithContentsOfFile:
     58            [[NSBundle mainBundle] pathForResource: @"Defaults"
     59                ofType: @"plist"]]];
    7860}
    7961
     
    10183    //set download folder
    10284    NSString * downloadChoice  = [fDefaults stringForKey: @"DownloadChoice"];
    103     fDownloadFolder = [fDefaults stringForKey: @"DownloadFolder"];
     85    fDownloadFolder = [[fDefaults stringForKey: @"DownloadFolder"] stringByExpandingTildeInPath];
    10486    [fDownloadFolder retain];
    10587
     
    127109    if ([fDefaults integerForKey: @"UploadLimit"] < 0)
    128110    {
    129         [fDefaults setObject: DEFAULT_UPLOAD forKey: @"UploadLimit"];
    130         [fDefaults setObject: @"NO" forKey: @"CheckUpload"];
     111        [fDefaults setInteger: 20 forKey: @"UploadLimit"];
     112        [fDefaults setBool: NO forKey: @"CheckUpload"];
    131113    }
    132114   
    133115    //set upload limit
    134     BOOL checkUpload = [[fDefaults stringForKey: @"CheckUpload"] isEqualToString:@"YES"];
     116    BOOL checkUpload = [fDefaults boolForKey: @"CheckUpload"];
    135117    int uploadLimit = [fDefaults integerForKey: @"UploadLimit"];
    136118   
     
    139121    [fUploadField setEnabled: checkUpload];
    140122   
    141     if (!checkUpload || uploadLimit == 0)
    142         uploadLimit = -1;
    143     tr_setUploadLimit( fHandle, uploadLimit );
     123    tr_setUploadLimit( fHandle, checkUpload ? uploadLimit : -1 );
    144124   
    145125    //set remove and quit prompts
    146     [fQuitCheck setState:([[fDefaults stringForKey: @"CheckQuit"]
    147                 isEqualToString:@"YES"] ? NSOnState : NSOffState)];
    148     [fRemoveCheck setState:([[fDefaults stringForKey: @"CheckRemove"]
    149                 isEqualToString:@"YES"] ? NSOnState : NSOffState)];
     126    [fQuitCheck setState: [fDefaults boolForKey: @"CheckQuit"] ?
     127        NSOnState : NSOffState];
     128    [fRemoveCheck setState: [fDefaults boolForKey: @"CheckRemove"] ?
     129        NSOnState : NSOffState];
     130
     131    //set dock badging
     132    [fBadgeCompletedCheck setState: [fDefaults boolForKey: @"BadgeCompleted"]];
     133    [fBadgeDownloadRateCheck setState: [fDefaults boolForKey: @"BadgeDownloadRate"]];
     134    [fBadgeUploadRateCheck setState: [fDefaults boolForKey: @"BadgeUploadRate"]];
     135
     136    /* Check for update */
     137    NSString * versionCheck  = [fDefaults stringForKey: @"VersionCheck"];
     138    if( [versionCheck isEqualToString: @"Daily"] )
     139        [fUpdatePopUp selectItemAtIndex: UPDATE_DAILY];
     140    else if( [versionCheck isEqualToString: @"Weekly"] )
     141        [fUpdatePopUp selectItemAtIndex: UPDATE_WEEKLY];
     142    else if( [versionCheck isEqualToString: @"Never"] )
     143        [fUpdatePopUp selectItemAtIndex: UPDATE_NEVER];
     144    else
     145    {
     146        [fDefaults setObject: @"Weekly" forKey: @"VersionCheck"];
     147        [fUpdatePopUp selectItemAtIndex: UPDATE_WEEKLY];
     148    }
    150149}
    151150
     
    214213    {
    215214        tr_setBindPort( fHandle, bindPort );
    216         [fDefaults setObject: [NSString stringWithFormat: @"%d", bindPort]
    217                     forKey: @"BindPort"];
     215        [fDefaults setInteger: bindPort forKey: @"BindPort"];
    218216    }
    219217}
     
    223221    BOOL checkUpload = [fUploadCheck state] == NSOnState;
    224222
    225     [fDefaults setObject: checkUpload ? @"YES" : @"NO"
    226                             forKey: @"CheckUpload"];
    227    
    228     [self setUploadLimit: sender];
     223    [fDefaults setBool: checkUpload forKey: @"CheckUpload"];
     224   
     225    [self setUploadLimit: nil];
    229226    [fUploadField setEnabled: checkUpload];
    230227}
     
    245242    else
    246243    {
    247         [fDefaults setObject: [NSString stringWithFormat: @"%d", uploadLimit]
    248             forKey: @"UploadLimit"];
     244        [fDefaults setInteger: uploadLimit forKey: @"UploadLimit"];
    249245    }
    250246   
     
    256252- (void) setQuitMessage: (id) sender
    257253{
    258     [fDefaults setObject: ([fQuitCheck state] == NSOnState ? @"YES" : @"NO")
    259                 forKey: @"CheckQuit"];
     254    [fDefaults setBool: ( [fQuitCheck state] == NSOnState )
     255        forKey: @"CheckQuit"];
    260256}
    261257
    262258- (void) setRemoveMessage: (id) sender
    263259{
    264     [fDefaults setObject: ([fRemoveCheck state] == NSOnState ? @"YES" : @"NO")
    265                 forKey: @"CheckRemove"];
     260    [fDefaults setBool: ( [fRemoveCheck state] == NSOnState )
     261        forKey: @"CheckRemove"];
     262}
     263
     264- (void) setBadge: (id) sender
     265{   
     266    BOOL state = [sender state];
     267   
     268    if (sender == fBadgeCompletedCheck)
     269        [fDefaults setBool: state forKey: @"BadgeCompleted"];
     270    else if (sender == fBadgeDownloadRateCheck)
     271        [fDefaults setBool: state forKey: @"BadgeDownloadRate"];
     272    else if (sender == fBadgeUploadRateCheck)
     273        [fDefaults setBool: state forKey: @"BadgeUploadRate"];
     274    else;
     275}
     276
     277- (void) setUpdate: (id) sender
     278{
     279    switch( [fUpdatePopUp indexOfSelectedItem] )
     280    {
     281        case UPDATE_DAILY:
     282            [fDefaults setObject: @"Daily" forKey: @"VersionCheck"];
     283            break;
     284        case UPDATE_WEEKLY:
     285            [fDefaults setObject: @"Weekly" forKey: @"VersionCheck"];
     286            break;
     287        case UPDATE_NEVER:
     288            [fDefaults setObject: @"Never" forKey: @"VersionCheck"];
     289            break;
     290    }
    266291}
    267292
  • branches/oneport/macosx/ProgressCell.h

    r15 r69  
    2424#define PROGRESSCELL_H
    2525
    26 #include <Cocoa/Cocoa.h>
    27 #include <transmission.h>
     26#import <Cocoa/Cocoa.h>
     27#import <transmission.h>
    2828
    2929@interface ProgressCell : NSCell
  • branches/oneport/macosx/ProgressCell.m

    r25 r69  
    2121 *****************************************************************************/
    2222
    23 #include "ProgressCell.h"
     23#import "ProgressCell.h"
     24#import "StringAdditions.h"
    2425
    2526@implementation ProgressCell
     
    122123
    123124    /* Update the strings to be displayed */
    124     fDlString = [NSString stringWithFormat:
    125         @"DL: %.2f KB/s", fStat->rateDownload];
    126     fUlString = [NSString stringWithFormat:
    127         @"UL: %.2f KB/s", fStat->rateUpload];
     125    fDlString = [@"DL: " stringByAppendingString:
     126                    [NSString stringForSpeed: fStat->rateDownload]];
     127    fUlString = [@"UL: " stringByAppendingString:
     128                    [NSString stringForSpeed: fStat->rateUpload]];
    128129
    129130    /* Reset our bitmap to the background image... */
     
    164165       two columns and the last four lines contain the shadow. */
    165166
    166     p      = (uint32_t *) [fProgressBmp bitmapData];
    167     p     += 2;
    168     end    = lrintf( floor( fStat->progress * 120 ) );
    169     colors = ( fStat->status & TR_STATUS_SEED ) ? kGreen : kBlue2;
     167    p   = (uint32_t *) [fProgressBmp bitmapData] + 2;
     168    end = lrintf( floor( fStat->progress * 120 ) );
     169
     170    if( fStat->status & TR_STATUS_SEED )
     171        colors = kGreen;
     172    else if( fStat->status & ( TR_STATUS_CHECK | TR_STATUS_DOWNLOAD ) )
     173        colors = kBlue2;
     174    else
     175        colors = kGray;
    170176
    171177    for( h = 0; h < 14; h++ )
  • branches/oneport/macosx/TorrentTableView.h

    r19 r69  
    1 #include <Cocoa/Cocoa.h>
    2 #include <transmission.h>
     1#import <Cocoa/Cocoa.h>
     2#import <transmission.h>
    33
    44@class Controller;
  • branches/oneport/macosx/TorrentTableView.m

    r19 r69  
    1 #include "TorrentTableView.h"
    2 #include "Controller.h"
     1#import "TorrentTableView.h"
     2#import "Controller.h"
    33
    44@implementation TorrentTableView
  • branches/oneport/macosx/Transmission.xcodeproj/project.pbxproj

    r19 r69  
    2424                4DA6FDC5091141AD00450CB1 /* ResumeOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */; };
    2525                4DA6FDC6091141AD00450CB1 /* ResumeOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDC4091141AD00450CB1 /* ResumeOn.png */; };
     26                4DE5CC9D0980656F00BE280E /* StringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DE5CC9C0980656F00BE280E /* StringAdditions.m */; };
     27                4DE5CCA70980735700BE280E /* Badger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DE5CCA60980735700BE280E /* Badger.m */; };
     28                4DE5CCA90980739100BE280E /* Badge.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DE5CCA80980739100BE280E /* Badge.png */; };
     29                4DE5CCBA0981D27700BE280E /* ResumeAll.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DE5CCB80981D27700BE280E /* ResumeAll.png */; };
     30                4DE5CCBB0981D27700BE280E /* PauseAll.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DE5CCB90981D27700BE280E /* PauseAll.png */; };
     31                4DE5CCCB0981D9BE00BE280E /* Defaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4DE5CCCA0981D9BE00BE280E /* Defaults.plist */; };
    2632                4DF0C5AB0899190500DD8943 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0C5A90899190500DD8943 /* Controller.m */; };
    2733                4DF0C5AE08991C1600DD8943 /* libtransmission.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DF0C5AD08991C1600DD8943 /* libtransmission.a */; };
     
    9197                4DA6FDC3091141AD00450CB1 /* ResumeOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeOff.png; path = Images/ResumeOff.png; sourceTree = "<group>"; };
    9298                4DA6FDC4091141AD00450CB1 /* ResumeOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeOn.png; path = Images/ResumeOn.png; sourceTree = "<group>"; };
     99                4DE5CC9B0980656F00BE280E /* StringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StringAdditions.h; sourceTree = "<group>"; };
     100                4DE5CC9C0980656F00BE280E /* StringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = StringAdditions.m; sourceTree = "<group>"; };
     101                4DE5CCA50980735700BE280E /* Badger.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Badger.h; sourceTree = "<group>"; };
     102                4DE5CCA60980735700BE280E /* Badger.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Badger.m; sourceTree = "<group>"; };
     103                4DE5CCA80980739100BE280E /* Badge.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Badge.png; path = Images/Badge.png; sourceTree = "<group>"; };
     104                4DE5CCB80981D27700BE280E /* ResumeAll.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeAll.png; path = Images/ResumeAll.png; sourceTree = "<group>"; };
     105                4DE5CCB90981D27700BE280E /* PauseAll.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseAll.png; path = Images/PauseAll.png; sourceTree = "<group>"; };
     106                4DE5CCCA0981D9BE00BE280E /* Defaults.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = Defaults.plist; sourceTree = "<group>"; };
    93107                4DF0C5A90899190500DD8943 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
    94108                4DF0C5AA0899190500DD8943 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
     
    128142                                4D364D9E091FBB2C00377D12 /* TorrentTableView.h */,
    129143                                4D364D9F091FBB2C00377D12 /* TorrentTableView.m */,
     144                                4DE5CC9B0980656F00BE280E /* StringAdditions.h */,
     145                                4DE5CC9C0980656F00BE280E /* StringAdditions.m */,
     146                                4DE5CCA50980735700BE280E /* Badger.h */,
     147                                4DE5CCA60980735700BE280E /* Badger.m */,
    130148                        );
    131149                        name = Classes;
     
    198216                                4D752E920913C949008EAAD4 /* Preferences.png */,
    199217                                4D8CEF90095870E00063BAEA /* Network.png */,
     218                                4DE5CCA80980739100BE280E /* Badge.png */,
     219                                4DE5CCB80981D27700BE280E /* ResumeAll.png */,
     220                                4DE5CCB90981D27700BE280E /* PauseAll.png */,
     221                                4DE5CCCA0981D9BE00BE280E /* Defaults.plist */,
    200222                                8D1107310486CEB800E47090 /* Info.plist */,
    201223                                089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
     
    288310                                4D752E930913C949008EAAD4 /* Preferences.png in Resources */,
    289311                                4D8CEF91095870E00063BAEA /* Network.png in Resources */,
     312                                4DE5CCA90980739100BE280E /* Badge.png in Resources */,
     313                                4DE5CCBA0981D27700BE280E /* ResumeAll.png in Resources */,
     314                                4DE5CCBB0981D27700BE280E /* PauseAll.png in Resources */,
     315                                4DE5CCCB0981D9BE00BE280E /* Defaults.plist in Resources */,
    290316                        );
    291317                        runOnlyForDeploymentPostprocessing = 0;
     
    304330                                4D118E1A08CB46B20033958F /* PrefsController.m in Sources */,
    305331                                4D364DA0091FBB2C00377D12 /* TorrentTableView.m in Sources */,
     332                                4DE5CC9D0980656F00BE280E /* StringAdditions.m in Sources */,
     333                                4DE5CCA70980735700BE280E /* Badger.m in Sources */,
    306334                        );
    307335                        runOnlyForDeploymentPostprocessing = 0;
  • branches/oneport/macosx/Utils.h

    r3 r69  
    2121 *****************************************************************************/
    2222
    23 static NSString * stringForFileSize( uint64_t size )
    24 {
    25     if( size < 1024 )
    26     {
    27         return [NSString stringWithFormat: @"%lld bytes", size];
    28     }
    29     if( size < 1048576 )
    30     {
    31         return [NSString stringWithFormat: @"%lld.%lld KB",
    32                 size / 1024, ( size % 1024 ) / 103];
    33     }
    34     if( size < 1073741824 )
    35     {
    36         return [NSString stringWithFormat: @"%lld.%lld MB",
    37                 size / 1048576, ( size % 1048576 ) / 104858];
    38     }
    39     return [NSString stringWithFormat: @"%lld.%lld GB",
    40             size / 1073741824, ( size % 1073741824 ) / 107374183];
    41 }
    42 
    43 static float widthForString( NSString * string, float fontSize )
    44 {
    45     NSMutableDictionary * attributes =
    46         [NSMutableDictionary dictionaryWithCapacity: 1];
    47     [attributes setObject: [NSFont messageFontOfSize: fontSize]
    48         forKey: NSFontAttributeName];
    49 
    50     return [string sizeWithAttributes: attributes].width;
    51 }
    52 
    5323#define NS_ELLIPSIS [NSString stringWithUTF8String: "\xE2\x80\xA6"]
    54 
    55 static NSString * stringFittingInWidth( NSString * oldString, float width,
    56                                         float fontSize )
    57 {
    58     NSString * newString  = NULL;
    59     unsigned   i;
    60 
    61     for( i = 0; i < [oldString length]; i++ )
    62     {
    63         newString = [NSString stringWithFormat: @"%@%@",
    64             [oldString substringToIndex: [oldString length] - i],
    65             i ? NS_ELLIPSIS : @""];
    66 
    67         if( widthForString( newString, fontSize ) <= width )
    68         {
    69             break;
    70         }
    71     }
    72     return newString;
    73 }
  • branches/oneport/macosx/main.m

    r1 r69  
    2121 *****************************************************************************/
    2222
    23 #include <Cocoa/Cocoa.h>
     23#import <Cocoa/Cocoa.h>
    2424
    2525int main( int argc, char ** argv )
Note: See TracChangeset for help on using the changeset viewer.