Changeset 3
- Timestamp:
- Jan 12, 2006, 6:29:20 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 8 deleted
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/AUTHORS
r1 r3 27 27 Martin Stadtmueller 28 28 + Icon tweaking 29 30 John Blitch 31 + Contextual menu patch -
trunk/Jamfile
r2 r3 34 34 macosx/ProgressCell.m 35 35 macosx/main.m 36 macosx/TorrentTableView.h 37 macosx/TorrentTableView.m 36 38 macosx/Transmission.xcodeproj/project.pbxproj 37 39 macosx/Transmission_Prefix.pch -
trunk/libtransmission/Jamfile
r1 r3 3 3 LIBTRANSMISSION_SRC = 4 4 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 ; 5 metainfo.c sha1.c utils.c upload.c fdlimit.c clients.c 6 completion.c ; 6 7 7 8 Library libtransmission.a : $(LIBTRANSMISSION_SRC) ; -
trunk/libtransmission/fastresume.h
r2 r3 102 102 char * path; 103 103 int * fileMTimes; 104 int i;105 104 uint8_t * blockBitfield; 106 105 … … 131 130 132 131 /* Build and write the bitfield for blocks */ 133 blockBitfield = calloc( ( tor->blockCount + 7 ) / 8, 1 ); 134 for( i = 0; i < tor->blockCount; i++ ) 135 { 136 if( tor->blockHave[i] < 0 ) 137 { 138 tr_bitfieldAdd( blockBitfield, i ); 139 } 140 } 132 blockBitfield = tr_cpBlockBitfield( tor->completion ); 141 133 fwrite( blockBitfield, ( tor->blockCount + 7 ) / 8, 1, file ); 142 free( blockBitfield );143 134 144 135 /* Write the 'slotPiece' table */ … … 223 214 blockBitfield = calloc( ( tor->blockCount + 7 ) / 8, 1 ); 224 215 fread( blockBitfield, ( tor->blockCount + 7 ) / 8, 1, file ); 225 tor->blockHaveCount = 0; 226 for( i = 0; i < tor->blockCount; i++ ) 227 { 228 if( tr_bitfieldHas( blockBitfield, i ) ) 229 { 230 tor->blockHave[i] = -1; 231 (tor->blockHaveCount)++; 232 } 233 } 216 tr_cpBlockBitfieldSet( tor->completion, blockBitfield ); 234 217 free( blockBitfield ); 235 218 … … 254 237 } 255 238 } 256 257 for( j = tr_pieceStartBlock( i );258 j < tr_pieceStartBlock( i ) + tr_pieceCountBlocks( i );259 j++ )260 {261 if( tor->blockHave[j] > -1 )262 {263 break;264 }265 }266 if( j >= tr_pieceStartBlock( i ) + tr_pieceCountBlocks( i ) )267 {268 // tr_dbg( "Piece %d is complete", i );269 tr_bitfieldAdd( tor->bitfield, i );270 }271 239 } 272 240 // tr_dbg( "Slot used: %d", io->slotsUsed ); -
trunk/libtransmission/fdlimit.c
r1 r3 35 35 #define STATUS_UNUSED 2 36 36 #define STATUS_USED 4 37 #define STATUS_CLOSING 8 37 38 int status; 38 39 … … 112 113 !strcmp( path, f->open[i].path ) ) 113 114 { 115 if( f->open[i].status & STATUS_CLOSING ) 116 { 117 /* Wait until the file is closed */ 118 tr_lockUnlock( f->lock ); 119 tr_wait( 10 ); 120 tr_lockLock( f->lock ); 121 i = -1; 122 continue; 123 } 114 124 winner = i; 115 125 goto done; … … 135 145 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 136 146 { 137 if( f->open[i].status & STATUS_USED)147 if( !( f->open[i].status & STATUS_UNUSED ) ) 138 148 { 139 149 continue; … … 148 158 if( winner >= 0 ) 149 159 { 160 /* Close the file: we mark it as closing then release the 161 lock while doing so, because fclose may take same time 162 and we don't want to block other threads */ 150 163 tr_dbg( "Closing %s", f->open[winner].path ); 164 f->open[winner].status = STATUS_CLOSING; 165 tr_lockUnlock( f->lock ); 151 166 fclose( f->open[winner].file ); 167 tr_lockLock( f->lock ); 152 168 goto open; 153 169 } -
trunk/libtransmission/inout.c
r1 r3 137 137 for( i = startBlock; i < endBlock; i++ ) 138 138 { 139 if( tor->blockHave[i] >= 0)139 if( !tr_cpBlockIsComplete( tor->completion, i ) ) 140 140 { 141 141 /* The piece is not complete */ … … 160 160 for( i = startBlock; i < endBlock; i++ ) 161 161 { 162 tor->blockHave[i] = 0; 163 tor->blockHaveCount -= 1; 162 tr_cpBlockRem( tor->completion, i ); 164 163 } 165 164 } … … 168 167 tr_inf( "Piece %d (slot %d): hash OK", index, 169 168 io->pieceSlot[index] ); 170 tr_ bitfieldAdd( tor->bitfield, index );169 tr_cpPieceAdd( tor->completion, index ); 171 170 } 172 171 … … 267 266 uint8_t * buf; 268 267 uint8_t hash[SHA_DIGEST_LENGTH]; 269 int startBlock, endBlock;270 268 271 269 io->pieceSlot = malloc( inf->pieceCount * sizeof( int ) ); … … 282 280 memset( io->pieceSlot, 0xFF, inf->pieceCount * sizeof( int ) ); 283 281 memset( io->slotPiece, 0xFF, inf->pieceCount * sizeof( int ) ); 284 memset( tor->bitfield, 0, ( inf->pieceCount + 7 ) / 8 );285 memset( tor->blockHave, 0, tor->blockCount );286 tor->blockHaveCount = 0;287 282 288 283 /* Check pieces */ … … 305 300 if( !memcmp( hash, &inf->pieces[20*j], SHA_DIGEST_LENGTH ) ) 306 301 { 307 int k;308 302 io->pieceSlot[j] = i; 309 303 io->slotPiece[i] = j; 310 tr_bitfieldAdd( tor->bitfield, j ); 311 312 startBlock = tr_pieceStartBlock( j ); 313 endBlock = startBlock + tr_pieceCountBlocks( j ); 314 for( k = startBlock; k < endBlock; k++ ) 315 { 316 tor->blockHave[k] = -1; 317 tor->blockHaveCount++; 318 } 304 305 tr_cpPieceAdd( tor->completion, j ); 319 306 break; 320 307 } … … 333 320 io->pieceSlot[inf->pieceCount - 1] = i; 334 321 io->slotPiece[i] = inf->pieceCount - 1; 335 tr_bitfieldAdd( tor->bitfield, inf->pieceCount - 1 ); 336 337 startBlock = tr_pieceStartBlock( inf->pieceCount - 1 ); 338 endBlock = startBlock + 339 tr_pieceCountBlocks( inf->pieceCount - 1 ); 340 for( j = startBlock; j < endBlock; j++ ) 341 { 342 tor->blockHave[j] = -1; 343 tor->blockHaveCount++; 344 } 322 323 tr_cpPieceAdd( tor->completion, inf->pieceCount - 1 ); 345 324 } 346 325 } … … 411 390 { 412 391 asprintf( &path, "%s/%s", tor->destination, inf->files[i].name ); 392 tr_lockUnlock( tor->lock ); 413 393 file = tr_fdFileOpen( tor->fdlimit, path ); 394 tr_lockLock( tor->lock ); 414 395 free( path ); 415 396 … … 422 403 (uint64_t) size ); 423 404 405 tr_lockUnlock( tor->lock ); 424 406 if( fseeko( file, posInFile, SEEK_SET ) ) 425 407 { 408 tr_lockLock( tor->lock ); 426 409 return 1; 427 410 } … … 430 413 if( fwrite( buf, willRead, 1, file ) != 1 ) 431 414 { 415 tr_lockLock( tor->lock ); 432 416 return 1; 433 417 } … … 437 421 if( fread( buf, willRead, 1, file ) != 1 ) 438 422 { 423 tr_lockLock( tor->lock ); 439 424 return 1; 440 425 } 441 426 } 442 427 tr_lockLock( tor->lock ); 443 428 tr_fdFileRelease( tor->fdlimit, file ); 444 429 -
trunk/libtransmission/internal.h
r2 r3 108 108 109 109 typedef struct tr_torrent_s tr_torrent_t; 110 typedef struct tr_completion_s tr_completion_t; 110 111 111 112 #include "bencode.h" … … 130 131 131 132 char * id; 133 char * key; 132 134 133 135 /* An escaped string used to include the hash in HTTP queries */ … … 143 145 int blockCount; 144 146 147 #if 0 145 148 /* Status for each block 146 149 -1 = we have it … … 149 152 int blockHaveCount; 150 153 uint8_t * bitfield; 154 #endif 155 tr_completion_t * completion; 151 156 152 157 volatile char die; … … 171 176 172 177 #include "utils.h" 178 #include "completion.h" 173 179 174 180 struct tr_handle_s … … 183 189 184 190 char id[21]; 191 char key[21]; 185 192 char prefsDirectory[256]; 186 193 }; -
trunk/libtransmission/peer.c
r2 r3 170 170 r = &peer->inRequests[j]; 171 171 block = tr_block( r->index,r->begin ); 172 if( tor->blockHave[block] > 0 ) 173 { 174 (tor->blockHave[block])--; 175 } 172 tr_cpDownloaderRem( tor->completion, block ); 176 173 } 177 174 if( !peer->amChoking ) … … 272 269 peer = tor->peers[i]; 273 270 274 /* Connect */ 275 if( ( peer->status & PEER_STATUS_IDLE ) && 276 !tr_fdSocketWillCreate( tor->fdlimit, 0 ) ) 277 { 278 peer->socket = tr_netOpen( peer->addr, peer->port ); 279 if( peer->socket < 0 ) 280 { 281 peer_dbg( "connection failed" ); 282 goto dropPeer; 283 } 284 peer->status = PEER_STATUS_CONNECTING; 285 } 286 287 /* Try to send handshake */ 288 if( peer->status & PEER_STATUS_CONNECTING ) 289 { 290 uint8_t buf[68]; 291 tr_info_t * inf = &tor->info; 292 293 buf[0] = 19; 294 memcpy( &buf[1], "BitTorrent protocol", 19 ); 295 memset( &buf[20], 0, 8 ); 296 memcpy( &buf[28], inf->hash, 20 ); 297 memcpy( &buf[48], tor->id, 20 ); 298 299 ret = tr_netSend( peer->socket, buf, 68 ); 271 if( peer->status < PEER_STATUS_HANDSHAKE ) 272 { 273 i++; 274 continue; 275 } 276 277 /* Try to read */ 278 for( ;; ) 279 { 280 if( peer->size < 1 ) 281 { 282 peer->size = 1024; 283 peer->buf = malloc( peer->size ); 284 } 285 else if( peer->pos >= peer->size ) 286 { 287 peer->size *= 2; 288 peer->buf = realloc( peer->buf, peer->size ); 289 } 290 ret = tr_netRecv( peer->socket, &peer->buf[peer->pos], 291 peer->size - peer->pos ); 300 292 if( ret & TR_NET_CLOSE ) 301 293 { … … 303 295 goto dropPeer; 304 296 } 305 else if( !( ret & TR_NET_BLOCK ) ) 306 { 307 peer_dbg( "SEND handshake" ); 308 peer->status = PEER_STATUS_HANDSHAKE; 309 } 310 } 311 312 /* Try to read */ 313 if( peer->status >= PEER_STATUS_HANDSHAKE ) 314 { 315 for( ;; ) 316 { 317 if( peer->size < 1 ) 318 { 319 peer->size = 1024; 320 peer->buf = malloc( peer->size ); 321 } 322 else if( peer->pos >= peer->size ) 323 { 324 peer->size *= 2; 325 peer->buf = realloc( peer->buf, peer->size ); 326 } 327 ret = tr_netRecv( peer->socket, &peer->buf[peer->pos], 328 peer->size - peer->pos ); 329 if( ret & TR_NET_CLOSE ) 330 { 331 peer_dbg( "connection closed" ); 332 goto dropPeer; 333 } 334 else if( ret & TR_NET_BLOCK ) 297 else if( ret & TR_NET_BLOCK ) 298 { 299 break; 300 } 301 peer->date = tr_date(); 302 peer->pos += ret; 303 if( parseBuf( tor, peer, ret ) ) 304 { 305 goto dropPeer; 306 } 307 } 308 309 if( peer->status < PEER_STATUS_CONNECTED ) 310 { 311 i++; 312 continue; 313 } 314 315 /* Try to write */ 316 writeBegin: 317 318 /* Send all smaller messages regardless of the upload cap */ 319 while( ( p = messagesPending( peer, &size ) ) ) 320 { 321 ret = tr_netSend( peer->socket, p, size ); 322 if( ret & TR_NET_CLOSE ) 323 { 324 goto dropPeer; 325 } 326 else if( ret & TR_NET_BLOCK ) 327 { 328 goto writeEnd; 329 } 330 messagesSent( peer, ret ); 331 } 332 333 /* Send pieces if we can */ 334 while( ( p = blockPending( tor, peer, &size ) ) ) 335 { 336 if( !tr_uploadCanUpload( tor->upload ) ) 337 { 338 break; 339 } 340 341 ret = tr_netSend( peer->socket, p, size ); 342 if( ret & TR_NET_CLOSE ) 343 { 344 goto dropPeer; 345 } 346 else if( ret & TR_NET_BLOCK ) 347 { 348 break; 349 } 350 351 blockSent( peer, ret ); 352 tr_uploadUploaded( tor->upload, ret ); 353 354 tor->uploaded[9] += ret; 355 peer->outTotal += ret; 356 peer->outDate = tr_date(); 357 358 /* In case this block is done, you may have messages 359 pending. Send them before we start the next block */ 360 goto writeBegin; 361 } 362 writeEnd: 363 364 /* Ask for a block whenever possible */ 365 if( !tr_cpIsSeeding( tor->completion ) && 366 !peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 ) 367 { 368 /* This peer is no use to us, and it seems there are 369 more */ 370 peer_dbg( "not interesting" ); 371 tr_peerRem( tor, i ); 372 continue; 373 } 374 375 if( peer->amInterested && !peer->peerChoking ) 376 { 377 int block; 378 while( peer->inRequestCount < OUR_REQUEST_COUNT ) 379 { 380 block = chooseBlock( tor, peer ); 381 if( block < 0 ) 335 382 { 336 383 break; 337 384 } 338 peer->date = tr_date(); 339 peer->pos += ret; 340 if( parseBuf( tor, peer, ret ) ) 341 { 342 goto dropPeer; 343 } 344 } 345 } 346 347 /* Try to write */ 348 writeBegin: 349 350 /* Send all smaller messages regardless of the upload cap */ 351 while( ( p = messagesPending( peer, &size ) ) ) 352 { 353 ret = tr_netSend( peer->socket, p, size ); 354 if( ret & TR_NET_CLOSE ) 355 { 356 goto dropPeer; 357 } 358 else if( ret & TR_NET_BLOCK ) 359 { 360 goto writeEnd; 361 } 362 messagesSent( peer, ret ); 363 } 364 365 /* Send pieces if we can */ 366 while( ( p = blockPending( tor, peer, &size ) ) ) 367 { 368 if( !tr_uploadCanUpload( tor->upload ) ) 369 { 370 break; 371 } 372 373 ret = tr_netSend( peer->socket, p, size ); 374 if( ret & TR_NET_CLOSE ) 375 { 376 goto dropPeer; 377 } 378 else if( ret & TR_NET_BLOCK ) 379 { 380 break; 381 } 382 383 blockSent( peer, ret ); 384 tr_uploadUploaded( tor->upload, ret ); 385 386 tor->uploaded[9] += ret; 387 peer->outTotal += ret; 388 peer->outDate = tr_date(); 389 390 /* In case this block is done, you may have messages 391 pending. Send them before we start the next block */ 392 goto writeBegin; 393 } 394 writeEnd: 395 396 /* Connected peers: ask for a block whenever possible */ 397 if( peer->status & PEER_STATUS_CONNECTED ) 398 { 399 if( tor->blockHaveCount < tor->blockCount && 400 !peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 ) 401 { 402 /* This peer is no use to us, and it seems there are 403 more */ 404 peer_dbg( "not interesting" ); 405 tr_peerRem( tor, i ); 406 continue; 407 } 408 409 if( peer->amInterested && !peer->peerChoking ) 410 { 411 int block; 412 while( peer->inRequestCount < OUR_REQUEST_COUNT ) 413 { 414 block = chooseBlock( tor, peer ); 415 if( block < 0 ) 416 { 417 break; 418 } 419 sendRequest( tor, peer, block ); 420 } 385 sendRequest( tor, peer, block ); 421 386 } 422 387 } -
trunk/libtransmission/peermessages.h
r2 r3 216 216 TR_HTONL( 1 + bitfieldSize, p ); 217 217 p[4] = 5; 218 memcpy( &p[5], t or->bitfield, bitfieldSize );218 memcpy( &p[5], tr_cpPieceBitfield( tor->completion ), bitfieldSize ); 219 219 220 220 peer_dbg( "SEND bitfield" ); … … 258 258 TR_HTONL( r->length, p + 13 ); 259 259 260 /* Remember that we have one more uploader for this block */ 261 (tor->blockHave[block])++; 260 tr_cpDownloaderAdd( tor->completion, block ); 262 261 263 262 peer_dbg( "SEND request %d/%d (%d bytes)", -
trunk/libtransmission/peerparse.h
r2 r3 52 52 { 53 53 r = &peer->inRequests[i]; 54 if( tor->blockHave[tr_block(r->index,r->begin)] > 0 ) 55 { 56 tor->blockHave[tr_block(r->index,r->begin)]--; 57 } 54 tr_cpDownloaderRem( tor->completion, tr_block(r->index,r->begin) ); 58 55 } 59 56 peer->inRequestCount = 0; … … 246 243 { 247 244 r = &peer->inRequests[j]; 248 if( tor->blockHave[tr_block(r->index,r->begin)] > 0 ) 249 { 250 tor->blockHave[tr_block(r->index,r->begin)]--; 251 } 245 tr_cpDownloaderRem( tor->completion, 246 tr_block(r->index,r->begin) ); 252 247 } 253 248 suckyClient = 1; … … 275 270 276 271 block = tr_block( r->index, r->begin ); 277 if( t or->blockHave[block] < 0)272 if( tr_cpBlockIsComplete( tor->completion, block ) ) 278 273 { 279 274 peer_dbg( "have this block already" ); … … 284 279 } 285 280 286 tor->blockHave[block] = -1; 287 tor->blockHaveCount += 1; 281 tr_cpBlockAdd( tor->completion, block ); 288 282 tr_ioWrite( tor->io, index, begin, len - 9, &p[8] ); 283 tr_cpDownloaderRem( tor->completion, block ); 289 284 290 285 sendCancel( tor, block ); 291 286 292 if( tr_ bitfieldHas( tor->bitfield, index ) )287 if( tr_cpPieceIsComplete( tor->completion, index ) ) 293 288 { 294 289 tr_peer_t * otherPeer; -
trunk/libtransmission/peerutils.h
r2 r3 164 164 } 165 165 166 /* Connect */ 167 if( ( peer->status & PEER_STATUS_IDLE ) && 168 !tr_fdSocketWillCreate( tor->fdlimit, 0 ) ) 169 { 170 peer->socket = tr_netOpen( peer->addr, peer->port ); 171 if( peer->socket < 0 ) 172 { 173 peer_dbg( "connection failed" ); 174 tr_fdSocketClosed( tor->fdlimit, 0 ); 175 return 1; 176 } 177 peer->status = PEER_STATUS_CONNECTING; 178 } 179 180 /* Try to send handshake */ 181 if( peer->status & PEER_STATUS_CONNECTING ) 182 { 183 uint8_t buf[68]; 184 tr_info_t * inf = &tor->info; 185 int ret; 186 187 buf[0] = 19; 188 memcpy( &buf[1], "BitTorrent protocol", 19 ); 189 memset( &buf[20], 0, 8 ); 190 memcpy( &buf[28], inf->hash, 20 ); 191 memcpy( &buf[48], tor->id, 20 ); 192 193 ret = tr_netSend( peer->socket, buf, 68 ); 194 if( ret & TR_NET_CLOSE ) 195 { 196 peer_dbg( "connection closed" ); 197 return 1; 198 } 199 else if( !( ret & TR_NET_BLOCK ) ) 200 { 201 peer_dbg( "SEND handshake" ); 202 peer->status = PEER_STATUS_HANDSHAKE; 203 } 204 } 205 166 206 return 0; 167 207 } … … 179 219 int i; 180 220 int bitfieldSize = ( inf->pieceCount + 7 ) / 8; 221 uint8_t * bitfield = tr_cpPieceBitfield( tor->completion ); 181 222 182 223 if( !peer->bitfield ) … … 188 229 for( i = 0; i < bitfieldSize; i++ ) 189 230 { 190 if( ( peer->bitfield[i] & ~( tor->bitfield[i]) ) & 0xFF )231 if( ( peer->bitfield[i] & ~(bitfield[i]) ) & 0xFF ) 191 232 { 192 233 return 1; … … 223 264 tr_info_t * inf = &tor->info; 224 265 225 int i, j; 226 int startBlock, endBlock, countBlocks; 266 int i; 227 267 int missingBlocks, minMissing; 228 268 int poolSize, * pool; … … 235 275 for( i = 0; i < inf->pieceCount; i++ ) 236 276 { 277 missingBlocks = tr_cpMissingBlocksForPiece( tor->completion, i ); 278 if( missingBlocks < 1 ) 279 { 280 /* We already have or are downloading all blocks */ 281 continue; 282 } 237 283 if( !tr_bitfieldHas( peer->bitfield, i ) ) 238 284 { 239 285 /* The peer doesn't have this piece */ 240 continue;241 }242 if( tr_bitfieldHas( tor->bitfield, i ) )243 {244 /* We already have it */245 continue;246 }247 248 /* Count how many blocks from this piece are missing */249 startBlock = tr_pieceStartBlock( i );250 countBlocks = tr_pieceCountBlocks( i );251 endBlock = startBlock + countBlocks;252 missingBlocks = countBlocks;253 for( j = startBlock; j < endBlock; j++ )254 {255 /* TODO: optimize */256 if( tor->blockHave[j] )257 {258 missingBlocks--;259 }260 if( missingBlocks > minMissing )261 {262 break;263 }264 }265 266 if( missingBlocks < 1 )267 {268 /* We are already downloading all blocks */269 286 continue; 270 287 } … … 332 349 333 350 /* Pick a block in this piece */ 334 startBlock = tr_pieceStartBlock( piece ); 335 endBlock = startBlock + tr_pieceCountBlocks( piece ); 336 for( i = startBlock; i < endBlock; i++ ) 337 { 338 if( !tor->blockHave[i] ) 339 { 340 block = i; 341 goto check; 342 } 343 } 344 351 block = tr_cpMissingBlockInPiece( tor->completion, piece ); 352 goto check; 353 } 354 355 free( pool ); 356 357 /* "End game" mode */ 358 minDownloading = 255; 359 block = -1; 360 for( i = 0; i < inf->pieceCount; i++ ) 361 { 362 int downloaders, block2; 363 if( !tr_bitfieldHas( peer->bitfield, i ) ) 364 { 365 /* The peer doesn't have this piece */ 366 continue; 367 } 368 if( tr_cpPieceIsComplete( tor->completion, i ) ) 369 { 370 /* We already have it */ 371 continue; 372 } 373 block2 = tr_cpMostMissingBlockInPiece( tor->completion, i, &downloaders ); 374 if( block2 > -1 && downloaders < minDownloading ) 375 { 376 block = block2; 377 minDownloading = downloaders; 378 } 379 } 380 381 check: 382 if( block < 0 ) 383 { 345 384 /* Shouldn't happen */ 346 385 return -1; 347 386 } 348 387 349 free( pool );350 351 /* "End game" mode */352 block = -1;353 minDownloading = TR_MAX_PEER_COUNT + 1;354 for( i = 0; i < tor->blockCount; i++ )355 {356 /* TODO: optimize */357 if( tr_bitfieldHas( peer->bitfield, tr_blockPiece( i ) ) &&358 tor->blockHave[i] >= 0 && tor->blockHave[i] < minDownloading )359 {360 block = i;361 minDownloading = tor->blockHave[i];362 }363 }364 365 if( block < 0 )366 {367 /* Shouldn't happen */368 return -1;369 }370 371 check:372 388 for( i = 0; i < peer->inRequestCount; i++ ) 373 389 { -
trunk/libtransmission/tracker.c
r1 r3 246 246 event = ""; 247 247 248 left = (uint64_t) ( tor->blockCount - tor->blockHaveCount ) * 249 (uint64_t) tor->blockSize; 250 left = MIN( left, inf->totalSize ); 248 left = tr_cpLeftBytes( tor->completion ); 251 249 252 250 ret = snprintf( (char *) tc->buf, tc->size, 253 "GET %s?info_hash=%s&peer_id=%s&port=%d&uploaded=%lld&" 254 "downloaded=%lld&left=%lld&compact=1&numwant=50%s " 255 "HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", 256 inf->trackerAnnounce, tor->hashString, tc->id, 257 tor->bindPort, tor->uploaded[9], tor->downloaded[9], 258 left, event, inf->trackerAddress ); 251 "GET %s?" 252 "info_hash=%s&" 253 "peer_id=%s&" 254 "port=%d&" 255 "uploaded=%lld&" 256 "downloaded=%lld&" 257 "left=%lld&" 258 "compact=1&" 259 "numwant=50&" 260 "key=%s" 261 "%s " 262 "HTTP/1.1\r\n" 263 "Host: %s\r\n" 264 "User-Agent: Transmission/%d.%d\r\n" 265 "Connection: close\r\n\r\n", 266 inf->trackerAnnounce, tor->hashString, tc->id, 267 tor->bindPort, tor->uploaded[9], tor->downloaded[9], 268 left, tor->key, event, inf->trackerAddress, 269 VERSION_MAJOR, VERSION_MINOR ); 259 270 260 271 ret = tr_netSend( tc->socket, tc->buf, ret ); … … 382 393 tc->leechers = beFoo->val.i; 383 394 } 384 if( tc->seeders + tc-> seeders >= 50 )395 if( tc->seeders + tc->leechers >= 50 ) 385 396 { 386 397 tc->hasManyPeers = 1; -
trunk/libtransmission/transmission.c
r2 r3 52 52 } 53 53 54 /* Random key */ 55 for( i = 0; i < 20; i++ ) 56 { 57 r = tr_rand( 36 ); 58 h->key[i] = ( r < 26 ) ? ( 'a' + r ) : ( '0' + r - 26 ) ; 59 } 60 54 61 /* Don't exit when writing on a broken socket */ 55 62 signal( SIGPIPE, SIG_IGN ); … … 165 172 tor->status = TR_STATUS_PAUSE; 166 173 tor->id = h->id; 174 tor->key = h->key; 167 175 168 176 /* Guess scrape URL */ … … 192 200 tor->blockCount = ( inf->totalSize + tor->blockSize - 1 ) / 193 201 tor->blockSize; 194 tor->blockHave = calloc( tor->blockCount, 1 ); 195 tor->bitfield = calloc( ( inf->pieceCount + 7 ) / 8, 1 ); 202 tor->completion = tr_cpInit( tor ); 196 203 197 204 tr_lockInit( &tor->lock ); … … 331 338 inf = &tor->info; 332 339 333 tr_lockLock( tor->lock );334 335 340 if( ( tor->status & TR_STATUS_STOPPED ) || 336 341 ( ( tor->status & TR_STATUS_STOPPING ) && … … 340 345 tor->status = TR_STATUS_PAUSE; 341 346 } 347 348 tr_lockLock( tor->lock ); 342 349 343 350 memcpy( &s[i].info, &tor->info, sizeof( tr_info_t ) ); … … 365 372 } 366 373 367 s[i].progress = (float) tor->blockHaveCount / (float) tor->blockCount; 368 374 s[i].progress = tr_cpCompletionAsFloat( tor->completion ); 369 375 s[i].rateDownload = rateDownload( tor ); 370 376 s[i].rateUpload = rateUpload( tor ); … … 376 382 else 377 383 { 378 s[i].eta = (float) ( tor->blockCount - tor->blockHaveCount) *379 (float) tor->blockSize / s[i].rateDownload / 1024.0;384 s[i].eta = (float) ( 1.0 - s[i].progress ) * 385 (float) inf->totalSize / s[i].rateDownload / 1024.0; 380 386 if( s[i].eta > 99 * 3600 + 59 * 60 + 59 ) 381 387 { … … 388 394 piece = j * inf->pieceCount / 120; 389 395 390 if( tr_ bitfieldHas( tor->bitfield, piece ) )396 if( tr_cpPieceIsComplete( tor->completion, piece ) ) 391 397 { 392 398 s[i].pieces[j] = -1; … … 431 437 { 432 438 /* Join the thread first */ 433 tr_lockLock( tor->lock );434 439 torrentReallyStop( h, t ); 435 tr_lockUnlock( tor->lock );436 440 } 437 441 … … 439 443 440 444 tr_lockClose( tor->lock ); 445 tr_cpClose( tor->completion ); 441 446 442 447 if( tor->destination ) … … 446 451 free( inf->pieces ); 447 452 free( inf->files ); 448 free( tor->blockHave );449 free( tor->bitfield );450 453 free( tor ); 451 454 … … 477 480 #endif 478 481 482 tr_lockLock( tor->lock ); 483 479 484 tor->io = tr_ioInit( tor ); 480 tor->status = ( tor->blockHaveCount < tor->blockCount) ?481 TR_STATUS_ DOWNLOAD : TR_STATUS_SEED;482 485 tor->status = tr_cpIsSeeding( tor->completion ) ? 486 TR_STATUS_SEED : TR_STATUS_DOWNLOAD; 487 483 488 while( !tor->die ) 484 489 { 485 490 date1 = tr_date(); 486 487 tr_lockLock( tor->lock );488 491 489 492 /* Are we finished ? */ 490 493 if( ( tor->status & TR_STATUS_DOWNLOAD ) && 491 t or->blockHaveCount >= tor->blockCount)494 tr_cpIsSeeding( tor->completion ) ) 492 495 { 493 496 /* Done */ … … 502 505 tr_trackerPulse( tor->tracker ); 503 506 504 tr_lockUnlock( tor->lock );505 506 507 if( tor->status & TR_STATUS_STOPPED ) 507 508 { … … 513 514 if( date2 < date1 + 20 ) 514 515 { 516 tr_lockUnlock( tor->lock ); 515 517 tr_wait( date1 + 20 - date2 ); 516 } 517 } 518 tr_lockLock( tor->lock ); 519 } 520 } 521 522 tr_lockUnlock( tor->lock ); 518 523 519 524 tr_ioClose( tor->io ); -
trunk/libtransmission/utils.h
r1 r3 76 76 } 77 77 78 static inline void tr_bitfieldRem( uint8_t * bitfield, int piece ) 79 { 80 bitfield[ piece / 8 ] &= ~( 1 << ( 7 - ( piece % 8 ) ) ); 81 } 82 78 83 #define tr_blockPiece(a) _tr_blockPiece(tor,a) 79 84 static inline int _tr_blockPiece( tr_torrent_t * tor, int block ) -
trunk/macosx/Controller.h
r2 r3 28 28 #include "PrefsController.h" 29 29 30 @class TorrentTableView; 31 30 32 @interface Controller : NSObject 31 33 { … … 34 36 tr_stat_t * fStat; 35 37 int fResumeOnWake[TR_MAX_TORRENT_COUNT]; 36 38 37 39 NSToolbar * fToolbar; 38 40 … … 42 44 43 45 IBOutlet NSWindow * fWindow; 44 IBOutlet NSTableView* fTableView;46 IBOutlet TorrentTableView * fTableView; 45 47 IBOutlet NSTextField * fTotalDLField; 46 48 IBOutlet NSTextField * fTotalULField; 49 IBOutlet NSMenu * fContextMenu; 47 50 48 51 IBOutlet NSPanel * fInfoPanel; … … 71 74 - (void) resumeTorrentWithIndex: (int) index; 72 75 - (void) removeTorrent: (id) sender; 76 - (void) removeTorrentDeleteFile: (id) sender; 77 - (void) removeTorrentDeleteData: (id) sender; 78 - (void) removeTorrentDeleteBoth: (id) sender; 79 - (void) removeTorrentWithIndex: (int) idx 80 deleteTorrent: (BOOL) deleteTorrent 81 deleteData: (BOOL) deleteData; 73 82 - (void) showInfo: (id) sender; 74 83 … … 76 85 - (void) sleepCallBack: (natural_t) messageType argument: 77 86 (void *) messageArgument; 87 88 - (NSMenu *) menuForIndex: (int) idx; 78 89 79 90 - (void) showMainWindow: (id) sender; -
trunk/macosx/Controller.m
r2 r3 26 26 #include "ProgressCell.h" 27 27 #include "Utils.h" 28 #include "TorrentTableView.h" 28 29 29 30 #define TOOLBAR_OPEN @"Toolbar Open" … … 31 32 #define TOOLBAR_PREFS @"Toolbar Preferences" 32 33 #define TOOLBAR_INFO @"Toolbar Info" 34 35 #define CONTEXT_PAUSE 1 36 #define CONTEXT_REMOVE 2 37 #define CONTEXT_REMOVE_TORRENT 3 38 #define CONTEXT_REMOVE_DATA 4 39 #define CONTEXT_REMOVE_BOTH 5 40 #define CONTEXT_INFO 6 33 41 34 42 static void sleepCallBack( void * controller, io_service_t y, … … 83 91 [fWindow setDelegate: self]; 84 92 85 [fTableView setDataSource: self];86 [fTableView setDelegate: self];87 88 93 NSTableColumn * tableColumn; 89 94 NameCell * nameCell; … … 93 98 progressCell = [[ProgressCell alloc] init]; 94 99 tableColumn = [fTableView tableColumnWithIdentifier: @"Name"]; 95 [nameCell setController: self];96 100 [tableColumn setDataCell: nameCell]; 97 101 [tableColumn setMinWidth: 10.0]; … … 397 401 } 398 402 403 404 - (void) removeTorrentWithIndex: (int) idx 405 deleteTorrent: (BOOL) deleteTorrent 406 deleteData: (BOOL) deleteData 407 { 408 BOOL torrentWarning = ![[NSUserDefaults standardUserDefaults] 409 boolForKey:@"SkipTorrentDeletionWarning"]; 410 BOOL dataWarning = ![[NSUserDefaults standardUserDefaults] 411 boolForKey:@"SkipDataDeletionWarning"]; 412 413 if ( ( torrentWarning && deleteTorrent ) || (dataWarning && deleteData ) ) 414 { 415 NSAlert *alert = [[[NSAlert alloc] init] autorelease]; 416 417 [alert addButtonWithTitle:@"No"]; 418 [alert addButtonWithTitle:@"Yes"]; 419 [alert setAlertStyle:NSWarningAlertStyle]; 420 [alert setMessageText:@"Are you sure you want to remove and delete?"]; 421 422 if ( (deleteTorrent && torrentWarning) && 423 !( dataWarning && deleteData ) ) 424 { 425 /* delete torrent warning YES, delete data warning NO */ 426 [alert setInformativeText:@"If you choose yes, the .torrent file will " 427 "be deleted. This cannot be undone."]; 428 } 429 else if( (deleteData && dataWarning) && 430 !( torrentWarning && deleteTorrent ) ) 431 { 432 /* delete torrent warning NO, delete data warning YES */ 433 [alert setInformativeText:@"If you choose yes, the downloaded data will " 434 "be deleted. This cannot be undone."]; 435 } 436 else 437 { 438 /* delete torrent warning YES, delete data warning YES */ 439 [alert setInformativeText:@"If you choose yes, both downloaded data and " 440 "torrent file will be deleted. This cannot be undone."]; 441 } 442 443 if ( [alert runModal] == NSAlertFirstButtonReturn ) 444 return; 445 } 446 447 if ( deleteData ) 448 { 449 tr_file_t * files = fStat[idx].info.files; 450 int i; 451 452 for ( i = 0; i < fStat[idx].info.fileCount; i++ ) 453 { 454 if ( -1 == remove([[NSString stringWithFormat:@"%s/%s", 455 fStat[idx].folder, 456 files[i].name] 457 cString]) ) 458 { 459 NSLog(@"remove(%s) failed, errno = %i", 460 files[i].name, 461 errno); 462 } 463 } 464 465 /* in some cases, we should remove fStat[idx].folder also. When? */ 466 } 467 468 if ( deleteTorrent ) 469 { 470 if ( -1 == remove( fStat[idx].info.torrent ) ) 471 { 472 NSLog(@"remove(%s) failed, errno = %i", 473 fStat[idx].info.torrent, 474 errno); 475 } 476 } 477 478 tr_torrentClose( fHandle, idx ); 479 [self updateUI: NULL]; 480 } 481 399 482 - (void) removeTorrent: (id) sender 400 483 { 401 tr_torrentClose( fHandle, [fTableView selectedRow] ); 402 [self updateUI: NULL]; 484 [self removeTorrentWithIndex: [fTableView selectedRow] deleteTorrent: NO deleteData: NO ]; 485 } 486 487 - (void) removeTorrentDeleteFile: (id) sender 488 { 489 [self removeTorrentWithIndex: [fTableView selectedRow] deleteTorrent: YES deleteData: NO]; 490 } 491 492 - (void) removeTorrentDeleteData: (id) sender 493 { 494 [self removeTorrentWithIndex: [fTableView selectedRow] deleteTorrent: NO deleteData: YES]; 495 } 496 497 - (void) removeTorrentDeleteBoth: (id) sender 498 { 499 [self removeTorrentWithIndex: [fTableView selectedRow] deleteTorrent: YES deleteData: YES]; 403 500 } 404 501 … … 426 523 } 427 524 fCount = tr_torrentStat( fHandle, &fStat ); 428 [fTableView reloadData];525 [fTableView updateUI: fStat]; 429 526 430 527 /* Update the global DL/UL rates */ … … 449 546 } 450 547 548 549 - (NSMenu *) menuForIndex: (int) idx 550 { 551 if ( idx < 0 || idx >= fCount ) 552 { 553 return nil; 554 } 555 556 int status = fStat[idx].status; 557 558 NSMenuItem *pauseItem = [fContextMenu itemWithTag: CONTEXT_PAUSE]; 559 NSMenuItem *removeItem = [fContextMenu itemAtIndex: 1]; 560 561 [pauseItem setTarget: self]; 562 563 if ( status & TR_STATUS_CHECK || 564 status & TR_STATUS_DOWNLOAD || 565 status & TR_STATUS_SEED ) 566 { 567 /* we can stop */ 568 [removeItem setEnabled: NO]; 569 [pauseItem setTitle: @"Pause"]; 570 [pauseItem setAction: @selector(stopTorrent:)]; 571 [pauseItem setEnabled: YES]; 572 } else { 573 /* we are stopped */ 574 [removeItem setEnabled: YES]; 575 [pauseItem setTitle: @"Resume"]; 576 [pauseItem setAction: @selector(resumeTorrent:)]; 577 /* don't allow resuming if we aren't in PAUSE */ 578 if ( !(status & TR_STATUS_PAUSE) ) 579 [pauseItem setEnabled: NO]; 580 } 581 582 return fContextMenu; 583 } 584 451 585 - (int) numberOfRowsInTableView: (NSTableView *) t 452 586 { … … 465 599 if( [[tableColumn identifier] isEqualToString: @"Name"] ) 466 600 { 467 [(NameCell *) cell setStat: &fStat[rowIndex] index: rowIndex];601 [(NameCell *) cell setStat: &fStat[rowIndex]]; 468 602 } 469 603 else if( [[tableColumn identifier] isEqualToString: @"Progress"] ) … … 519 653 520 654 /* Update info window */ 521 [fInfoTitle setStringValue: [NSString stringWith CString:655 [fInfoTitle setStringValue: [NSString stringWithUTF8String: 522 656 fStat[row].info.name]]; 523 657 [fInfoTracker setStringValue: [NSString stringWithFormat: -
trunk/macosx/English.lproj/MainMenu.nib/classes.nib
r1 r3 8 8 openShowSheet = id; 9 9 removeTorrent = id; 10 removeTorrentDeleteBoth = id; 11 removeTorrentDeleteData = id; 12 removeTorrentDeleteFile = id; 10 13 resumeTorrent = id; 11 14 showInfo = id; … … 17 20 OUTLETS = { 18 21 fAdvancedBarItem = NSMenuItem; 22 fContextMenu = NSMenu; 19 23 fInfoAnnounce = NSTextField; 20 24 fInfoDownloaded = NSTextField; … … 50 54 }; 51 55 SUPERCLASS = NSObject; 56 }, 57 { 58 CLASS = TorrentTableView; 59 LANGUAGE = ObjC; 60 OUTLETS = {fController = Controller; }; 61 SUPERCLASS = NSTableView; 52 62 } 53 63 ); -
trunk/macosx/English.lproj/MainMenu.nib/info.nib
r1 r3 4 4 <dict> 5 5 <key>IBDocumentLocation</key> 6 <string> 204 84 361 432 0 0 1440 878</string>6 <string>188 334 361 432 0 0 1280 832 </string> 7 7 <key>IBEditorPositions</key> 8 8 <dict> 9 9 <key>29</key> 10 10 <string>105 768 371 44 0 0 1280 832 </string> 11 <key>456</key> 12 <string>174 512 147 87 0 0 1280 832 </string> 11 13 </dict> 12 14 <key>IBFramework Version</key> 13 <string>4 39.0</string>15 <string>443.0</string> 14 16 <key>IBOldestOS</key> 15 17 <integer>3</integer> 16 18 <key>IBOpenObjects</key> 17 19 <array> 20 <integer>456</integer> 18 21 <integer>21</integer> 19 <integer>29</integer>20 <integer>273</integer>21 <integer>343</integer>22 22 </array> 23 23 <key>IBSystem Version</key> 24 <string>8 C46</string>24 <string>8F46</string> 25 25 </dict> 26 26 </plist> -
trunk/macosx/NameCell.h
r2 r3 30 30 @interface NameCell : NSCell 31 31 { 32 Controller * fController; 33 tr_stat_t * fStat; 34 int fIndex; 35 NSRect fPauseRect; 36 NSRect fRevealRect; 37 NSPoint fClickPoint; 32 NSString * fNameString; 33 NSString * fSizeString; 34 NSString * fTimeString; 35 NSString * fPeersString; 38 36 } 39 - (void) setController: (Controller *) controller; 40 - (void) setStat: (tr_stat_t *) stat index: (int) index; 37 - (void) setStat: (tr_stat_t *) stat; 41 38 @end 42 39 -
trunk/macosx/NameCell.m
r2 r3 26 26 @implementation NameCell 27 27 28 - (void) set Controller: (Controller *) controller28 - (void) setStat: (tr_stat_t *) stat 29 29 { 30 fController = controller; 31 } 30 fNameString = [NSString stringWithUTF8String: stat->info.name]; 31 fSizeString = [NSString stringWithFormat: @" (%@)", 32 stringForFileSize( stat->info.totalSize )]; 33 fTimeString = @""; 34 fPeersString = @""; 32 35 33 - (void) setStat: (tr_stat_t *) stat index: (int) idx 34 { 35 fStat = stat; 36 fIndex = idx; 36 if( stat->status & TR_STATUS_PAUSE ) 37 { 38 fTimeString = [NSString stringWithFormat: 39 @"Paused (%.2f %%)", 100 * stat->progress]; 40 } 41 else if( stat->status & TR_STATUS_CHECK ) 42 { 43 fTimeString = [NSString stringWithFormat: 44 @"Checking existing files (%.2f %%)", 100 * stat->progress]; 45 } 46 else if( stat->status & TR_STATUS_DOWNLOAD ) 47 { 48 if( stat->eta < 0 ) 49 { 50 fTimeString = [NSString stringWithFormat: 51 @"Finishing in --:--:-- (%.2f %%)", 100 * stat->progress]; 52 } 53 else 54 { 55 fTimeString = [NSString stringWithFormat: 56 @"Finishing in %02d:%02d:%02d (%.2f %%)", 57 stat->eta / 3600, ( stat->eta / 60 ) % 60, 58 stat->eta % 60, 100 * stat->progress]; 59 } 60 fPeersString = [NSString stringWithFormat: 61 @"Downloading from %d of %d peer%s", 62 stat->peersUploading, stat->peersTotal, 63 ( stat->peersTotal == 1 ) ? "" : "s"]; 64 } 65 else if( stat->status & TR_STATUS_SEED ) 66 { 67 fTimeString = [NSString stringWithFormat: 68 @"Seeding, uploading to %d of %d peer%s", 69 stat->peersDownloading, stat->peersTotal, 70 ( stat->peersTotal == 1 ) ? "" : "s"]; 71 } 72 else if( stat->status & TR_STATUS_STOPPING ) 73 { 74 fTimeString = @"Stopping..."; 75 } 76 77 if( ( stat->status & ( TR_STATUS_DOWNLOAD | TR_STATUS_SEED ) ) && 78 ( stat->status & TR_TRACKER_ERROR ) ) 79 { 80 fPeersString = [NSString stringWithFormat: @"%@%@", 81 @"Error: ", [NSString stringWithUTF8String: stat->error]]; 82 } 37 83 } 38 84 39 85 - (void) drawWithFrame: (NSRect) cellFrame inView: (NSView *) view 40 86 { 87 NSString * string; 88 NSPoint pen; 89 NSMutableDictionary * attributes; 90 41 91 if( ![view lockFocusIfCanDraw] ) 42 92 { … … 44 94 } 45 95 46 NSString * nameString = NULL, * timeString = @"", * peersString = @"";47 NSMutableDictionary * attributes; 96 pen = cellFrame.origin; 97 48 98 attributes = [NSMutableDictionary dictionaryWithCapacity: 1]; 49 NSPoint pen = cellFrame.origin;50 51 NSString * sizeString = [NSString stringWithFormat: @" (%@)",52 stringForFileSize( fStat->info.totalSize )];53 54 nameString = [NSString stringWithFormat: @"%@%@",55 stringFittingInWidth( fStat->info.name, cellFrame.size.width -56 35 - widthForString( sizeString, 12 ), 12 ),57 sizeString];58 59 if( fStat->status & TR_STATUS_PAUSE )60 {61 timeString = [NSString stringWithFormat:62 @"Paused (%.2f %%)", 100 * fStat->progress];63 peersString = @"";64 }65 else if( fStat->status & TR_STATUS_CHECK )66 {67 timeString = [NSString stringWithFormat:68 @"Checking existing files (%.2f %%)", 100 * fStat->progress];69 peersString = @"";70 }71 else if( fStat->status & TR_STATUS_DOWNLOAD )72 {73 if( fStat->eta < 0 )74 {75 timeString = [NSString stringWithFormat:76 @"Finishing in --:--:-- (%.2f %%)", 100 * fStat->progress];77 }78 else79 {80 timeString = [NSString stringWithFormat:81 @"Finishing in %02d:%02d:%02d (%.2f %%)",82 fStat->eta / 3600, ( fStat->eta / 60 ) % 60,83 fStat->eta % 60, 100 * fStat->progress];84 }85 peersString = [NSString stringWithFormat:86 @"Downloading from %d of %d peer%s",87 fStat->peersUploading, fStat->peersTotal,88 ( fStat->peersTotal == 1 ) ? "" : "s"];89 }90 else if( fStat->status & TR_STATUS_SEED )91 {92 timeString = [NSString stringWithFormat:93 @"Seeding, uploading to %d of %d peer%s",94 fStat->peersDownloading, fStat->peersTotal,95 ( fStat->peersTotal == 1 ) ? "" : "s"];96 peersString = @"";97 }98 else if( fStat->status & TR_STATUS_STOPPING )99 {100 timeString = @"Stopping...";101 peersString = @"";102 }103 104 if( ( fStat->status & ( TR_STATUS_DOWNLOAD | TR_STATUS_SEED ) ) &&105 ( fStat->status & TR_TRACKER_ERROR ) )106 {107 peersString = [NSString stringWithFormat: @"%@%@",108 @"Error: ", stringFittingInWidth( fStat->error,109 cellFrame.size.width - 40 -110 widthForString( @"Error: ", 10 ), 10 )];111 }112 113 99 [attributes setObject: [NSFont messageFontOfSize:12.0] 114 100 forKey: NSFontAttributeName]; 115 101 116 102 pen.x += 5; pen.y += 5; 117 [nameString drawAtPoint: pen withAttributes: attributes]; 103 string = [NSString stringWithFormat: @"%@%@", 104 stringFittingInWidth( fNameString, cellFrame.size.width - 105 35 - widthForString( fSizeString, 12 ), 12 ), fSizeString]; 106 [string drawAtPoint: pen withAttributes: attributes]; 118 107 119 108 [attributes setObject: [NSFont messageFontOfSize:10.0] … … 121 110 122 111 pen.x += 5; pen.y += 20; 123 [ timeString drawAtPoint: pen withAttributes: attributes];112 [fTimeString drawAtPoint: pen withAttributes: attributes]; 124 113 125 114 pen.x += 0; pen.y += 15; 126 [peersString drawAtPoint: pen withAttributes: attributes]; 127 128 /* "Pause" button */ 129 fPauseRect = NSMakeRect( cellFrame.origin.x + cellFrame.size.width - 19, 130 cellFrame.origin.y + cellFrame.size.height - 38, 131 14, 14 ); 132 NSImage * pauseImage = NULL; 133 if( fStat->status & TR_STATUS_PAUSE ) 134 { 135 if( NSPointInRect( fClickPoint, fPauseRect ) ) 136 { 137 pauseImage = [NSImage imageNamed: @"ResumeOn.png"]; 138 } 139 else 140 { 141 pauseImage = [NSImage imageNamed: @"ResumeOff.png"]; 142 } 143 } 144 else if( fStat->status & 145 ( TR_STATUS_CHECK | TR_STATUS_DOWNLOAD | TR_STATUS_SEED ) ) 146 { 147 if( NSPointInRect( fClickPoint, fPauseRect ) ) 148 { 149 pauseImage = [NSImage imageNamed: @"PauseOn.png"]; 150 } 151 else 152 { 153 pauseImage = [NSImage imageNamed: @"PauseOff.png"]; 154 } 155 } 156 if( pauseImage ) 157 { 158 pen.x = fPauseRect.origin.x; 159 pen.y = fPauseRect.origin.y + 14; 160 [pauseImage compositeToPoint: pen operation: NSCompositeSourceOver]; 161 } 162 163 /* "Reveal in Finder" button */ 164 fRevealRect = NSMakeRect( cellFrame.origin.x + cellFrame.size.width - 19, 165 cellFrame.origin.y + cellFrame.size.height - 19, 166 14, 14 ); 167 NSImage * revealImage; 168 if( NSPointInRect( fClickPoint, fRevealRect ) ) 169 { 170 revealImage = [NSImage imageNamed: @"RevealOn.png"]; 171 } 172 else 173 { 174 revealImage = [NSImage imageNamed: @"RevealOff.png"]; 175 } 176 pen.x = fRevealRect.origin.x; 177 pen.y = fRevealRect.origin.y + 14; 178 [revealImage compositeToPoint: pen operation: NSCompositeSourceOver]; 115 string = stringFittingInWidth( fPeersString, 116 cellFrame.size.width - 40, 10 ); 117 [string drawAtPoint: pen withAttributes: attributes]; 179 118 180 119 [view unlockFocus]; 181 120 } 182 121 183 /* Track mouse as long as button is down */184 - (BOOL) startTrackingAt: (NSPoint) start inView: (NSView *) v185 {186 fClickPoint = start;187 return YES;188 }189 - (BOOL) continueTracking: (NSPoint) last at: (NSPoint) current190 inView: (NSView *) v191 {192 fClickPoint = current;193 return YES;194 }195 196 - (void) stopTracking: (NSPoint) last at:(NSPoint) stop197 inView: (NSView *) v mouseIsUp: (BOOL) flag198 {199 if( flag )200 {201 if( NSPointInRect( stop, fRevealRect ) )202 {203 /* Reveal in Finder */204 NSString * string = [NSString stringWithFormat:205 @"tell application \"Finder\"\nactivate\nreveal (POSIX file \"%s/%s\")\nend tell",206 fStat->folder, fStat->info.name];207 NSAppleScript * appleScript;208 appleScript = [[NSAppleScript alloc] initWithSource: string];209 NSDictionary * error;210 if( ![appleScript executeAndReturnError: &error] )211 {212 printf( "Reveal in Finder: AppleScript failed\n" );213 }214 [appleScript release];215 }216 else if( NSPointInRect( stop, fPauseRect ) )217 {218 /* Pause, resume */219 if( fStat->status & TR_STATUS_PAUSE )220 {221 [fController resumeTorrentWithIndex: fIndex];222 }223 else if( fStat->status & ( TR_STATUS_CHECK |224 TR_STATUS_DOWNLOAD | TR_STATUS_SEED ) )225 {226 [fController stopTorrentWithIndex: fIndex];227 }228 }229 }230 fClickPoint = NSMakePoint(0,0);231 }232 233 122 @end -
trunk/macosx/Transmission.xcodeproj/project.pbxproj
r2 r3 13 13 4D118E1A08CB46B20033958F /* PrefsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D118E1908CB46B20033958F /* PrefsController.m */; }; 14 14 4D2784370905709500687951 /* Transmission.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4D2784360905709500687951 /* Transmission.icns */; }; 15 4D364DA0091FBB2C00377D12 /* TorrentTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D364D9F091FBB2C00377D12 /* TorrentTableView.m */; }; 15 16 4D3EA0AA08AE13C600EA10C2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D3EA0A908AE13C600EA10C2 /* IOKit.framework */; }; 16 17 4D6DAAC6090CE00500F43C22 /* RevealOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D6DAAC4090CE00500F43C22 /* RevealOff.png */; }; … … 77 78 4D118E1908CB46B20033958F /* PrefsController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PrefsController.m; sourceTree = "<group>"; }; 78 79 4D2784360905709500687951 /* Transmission.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = Transmission.icns; path = Images/Transmission.icns; sourceTree = "<group>"; }; 80 4D364D9E091FBB2C00377D12 /* TorrentTableView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TorrentTableView.h; sourceTree = "<group>"; }; 81 4D364D9F091FBB2C00377D12 /* TorrentTableView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = TorrentTableView.m; sourceTree = "<group>"; }; 79 82 4D3EA0A908AE13C600EA10C2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; }; 80 83 4D6DAAC4090CE00500F43C22 /* RevealOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = RevealOff.png; path = Images/RevealOff.png; sourceTree = "<group>"; }; … … 121 124 4D118E1808CB46B20033958F /* PrefsController.h */, 122 125 4D118E1908CB46B20033958F /* PrefsController.m */, 126 4D364D9E091FBB2C00377D12 /* TorrentTableView.h */, 127 4D364D9F091FBB2C00377D12 /* TorrentTableView.m */, 123 128 ); 124 129 name = Classes; … … 294 299 4D096C13089FB4E20091B166 /* ProgressCell.m in Sources */, 295 300 4D118E1A08CB46B20033958F /* PrefsController.m in Sources */, 301 4D364DA0091FBB2C00377D12 /* TorrentTableView.m in Sources */, 296 302 ); 297 303 runOnlyForDeploymentPostprocessing = 0; -
trunk/macosx/Utils.h
r1 r3 51 51 } 52 52 53 static NSString * stringFittingInWidth( char * string, float width, 53 #define NS_ELLIPSIS [NSString stringWithUTF8String: "\xE2\x80\xA6"] 54 55 static NSString * stringFittingInWidth( NSString * oldString, float width, 54 56 float fontSize ) 55 57 { 56 NSString * nsString = NULL; 57 char * foo = strdup( string ); 58 int i; 58 NSString * newString = NULL; 59 unsigned i; 59 60 60 for( i = strlen( string ); i > 0; i--)61 for( i = 0; i < [oldString length]; i++ ) 61 62 { 62 foo[i] = '\0'; 63 nsString = [NSString stringWithFormat: @"%s%@", 64 foo, ( i - strlen( string ) ? [NSString 65 stringWithUTF8String:"\xE2\x80\xA6"] : @"" )]; 63 newString = [NSString stringWithFormat: @"%@%@", 64 [oldString substringToIndex: [oldString length] - i], 65 i ? NS_ELLIPSIS : @""]; 66 66 67 if( widthForString( n sString, fontSize ) <= width )67 if( widthForString( newString, fontSize ) <= width ) 68 68 { 69 69 break; 70 70 } 71 71 } 72 free( foo ); 73 return nsString; 72 return newString; 74 73 } -
trunk/transmissioncli.c
r1 r3 28 28 #include <signal.h> 29 29 #include <transmission.h> 30 #ifdef SYS_BEOS 31 #include <kernel/OS.h> 32 #define usleep snooze 33 #endif 30 34 31 35 #define USAGE \
Note: See TracChangeset
for help on using the changeset viewer.