diff --git a/macosx/Controller.m b/macosx/Controller.m
index e58afc94b..39a6ae35e 100644
--- a/macosx/Controller.m
+++ b/macosx/Controller.m
@@ -1343,7 +1343,7 @@ static void sleepCallBack(void * controller, io_service_t y, natural_t messageTy
{
enumerator = [fTorrents objectEnumerator];
while ((torrent = [enumerator nextObject]))
- if ([torrent isActive] && ![torrent isError])
+ if ([torrent isActive] && ![torrent isStalled] && ![torrent isError])
{
if ([torrent allDownloaded])
desiredSeedActive--;
diff --git a/macosx/Defaults.plist b/macosx/Defaults.plist
index 85f786d27..9576a34c8 100644
--- a/macosx/Defaults.plist
+++ b/macosx/Defaults.plist
@@ -24,6 +24,8 @@
CheckRemoveDownloading
+ CheckStalled
+
CheckUpload
DeleteOriginalTorrent
@@ -98,6 +100,8 @@
10
SpeedLimitUploadLimit
10
+ StalledSeconds
+ 300
StatusBar
UpdateCheck
diff --git a/macosx/English.lproj/PrefsWindow.nib/classes.nib b/macosx/English.lproj/PrefsWindow.nib/classes.nib
index d2b94f387..0bf38b9be 100644
--- a/macosx/English.lproj/PrefsWindow.nib/classes.nib
+++ b/macosx/English.lproj/PrefsWindow.nib/classes.nib
@@ -25,6 +25,8 @@
setRatioStop = id;
setSound = id;
setSpeedLimit = id;
+ setStalled = id;
+ setStalledSeconds = id;
setUpdate = id;
};
CLASS = PrefsController;
@@ -51,6 +53,7 @@
fSeedingSoundPopUp = NSPopUpButton;
fSpeedLimitDownloadField = NSTextField;
fSpeedLimitUploadField = NSTextField;
+ fStalledField = NSTextField;
fTransfersView = NSView;
fUpdatePopUp = NSPopUpButton;
fUploadField = NSTextField;
diff --git a/macosx/English.lproj/PrefsWindow.nib/info.nib b/macosx/English.lproj/PrefsWindow.nib/info.nib
index 0e2a3759b..fff0485c7 100644
--- a/macosx/English.lproj/PrefsWindow.nib/info.nib
+++ b/macosx/English.lproj/PrefsWindow.nib/info.nib
@@ -7,11 +7,11 @@
IBEditorPositions
153
- 206 273 563 268 0 0 1152 842
+ 294 444 563 268 0 0 1152 842
28
294 421 563 313 0 0 1152 842
41
- 294 425 563 305 0 0 1152 842
+ 70 441 563 305 0 0 1152 842
66
294 506 563 144 0 0 1152 842
diff --git a/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib b/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib
index b63661b01..6a0d2f3e2 100644
Binary files a/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib and b/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib differ
diff --git a/macosx/PrefsController.h b/macosx/PrefsController.h
index 6e8c2b0dd..1725320c7 100644
--- a/macosx/PrefsController.h
+++ b/macosx/PrefsController.h
@@ -39,7 +39,7 @@
IBOutlet NSPopUpButton * fFolderPopUp, * fIncompleteFolderPopUp, * fImportFolderPopUp,
* fDownloadSoundPopUp, * fSeedingSoundPopUp;
- IBOutlet NSTextField * fRatioStopField, * fQueueDownloadField, * fQueueSeedField;
+ IBOutlet NSTextField * fRatioStopField, * fQueueDownloadField, * fQueueSeedField, * fStalledField;
NSArray * fSounds;
@@ -68,6 +68,9 @@
- (void) setQueue: (id) sender;
- (void) setQueueNumber: (id) sender;
+- (void) setStalled: (id) sender;
+- (void) setStalledSeconds: (id) sender;
+
- (void) setDownloadLocation: (id) sender;
- (void) folderSheetShow: (id) sender;
- (void) incompleteFolderSheetShow: (id) sender;
diff --git a/macosx/PrefsController.m b/macosx/PrefsController.m
index c7469f8b3..232972d7c 100644
--- a/macosx/PrefsController.m
+++ b/macosx/PrefsController.m
@@ -155,6 +155,9 @@
[fQueueDownloadField setIntValue: [fDefaults integerForKey: @"QueueDownloadNumber"]];
[fQueueSeedField setIntValue: [fDefaults integerForKey: @"QueueSeedNumber"]];
+ //set stalled value
+ [fStalledField setIntValue: [fDefaults integerForKey: @"StalledSeconds"]];
+
//set update check
NSString * updateCheck = [fDefaults stringForKey: @"UpdateCheck"];
if ([updateCheck isEqualToString: @"Weekly"])
@@ -484,10 +487,28 @@
}
[fDefaults setInteger: limit forKey: download ? @"QueueDownloadNumber" : @"QueueSeedNumber"];
-
[self setQueue: nil];
}
+- (void) setStalled: (id) sender
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: self];
+}
+
+- (void) setStalledSeconds: (id) sender
+{
+ int seconds = [sender intValue];
+ if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%d", seconds]] || seconds < 0)
+ {
+ NSBeep();
+ [sender setIntValue: [fDefaults integerForKey: @"StalledSeconds"]];
+ return;
+ }
+
+ [fDefaults setInteger: seconds forKey: @"StalledSeconds"];
+ [self setQueueStalled: nil];
+}
+
- (void) setDownloadLocation: (id) sender
{
switch ([fFolderPopUp indexOfSelectedItem])
diff --git a/macosx/Torrent.h b/macosx/Torrent.h
index 787a5efe5..e55170f84 100644
--- a/macosx/Torrent.h
+++ b/macosx/Torrent.h
@@ -56,7 +56,7 @@
int fUploadLimit, fDownloadLimit;
float fRatioLimit;
int fCheckUpload, fCheckDownload, fRatioSetting;
- BOOL fFinishedSeeding, fWaitToStart, fError, fChecking;
+ BOOL fFinishedSeeding, fWaitToStart, fError, fChecking, fStalled;
int fOrderValue;
@@ -205,6 +205,9 @@
- (NSDate *) dateCompleted;
- (NSDate *) dateActivity;
+- (int) stalledSeconds;
+- (BOOL) isStalled;
+
- (NSNumber *) stateSortKey;
- (NSNumber *) progressSortKey;
- (NSNumber *) ratioSortKey;
diff --git a/macosx/Torrent.m b/macosx/Torrent.m
index 2f3c38c31..cb258244c 100644
--- a/macosx/Torrent.m
+++ b/macosx/Torrent.m
@@ -445,21 +445,23 @@ static uint32_t kRed = BE(0xFF6450FF), //255, 100, 80
break;
}
- if (wasChecking && !fChecking)
- [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateQueue" object: self];
-
- if ([self isError])
- {
- [statusString setString: [NSLocalizedString(@"Error: ", "Torrent -> status string") stringByAppendingString:
- [self errorMessage]]];
- }
-
+ //check for error
BOOL wasError = fError;
- if ((fError = fStat->cannotConnect))
- {
- if (!wasError && [self isActive])
- [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateQueue" object: self];
- }
+ if ((fError = [self isError]))
+ [statusString setString: [NSLocalizedString(@"Error: ", "Torrent -> status string")
+ stringByAppendingString: [self errorMessage]]];
+
+ //check if stalled
+ BOOL wasStalled = fStalled;
+ fStalled = [fDefaults boolForKey: @"CheckStalled"]
+ && [fDefaults integerForKey: @"StalledSeconds"] < [self stalledSeconds];
+ if (!fError && fStalled)
+ [statusString setString: [NSLocalizedString(@"Stalled, ", "Torrent -> status string")
+ stringByAppendingString: statusString]];
+
+ //update queue for checking (from downloading to seeding), stalled, or error
+ if ((wasChecking && !fChecking) || (!wasStalled && fStalled) || (!wasError && fError && [self isActive]))
+ [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateQueue" object: self];
if ([self isActive] && fStat->status != TR_STATUS_CHECK )
{
@@ -1355,6 +1357,24 @@ static uint32_t kRed = BE(0xFF6450FF), //255, 100, 80
return date > 0 ? [NSDate dateWithTimeIntervalSince1970: date] : fDateActivity;
}
+- (int) stalledSeconds
+{
+ if (![self isActive])
+ return -1;
+
+ NSDate * started = [NSDate dateWithTimeIntervalSince1970: fStat->startDate / 1000],
+ * activity = [self dateActivity];
+ if (!activity || [started compare: activity] == NSOrderedDescending)
+ return -1.0 * [started timeIntervalSinceNow];
+ else
+ return -1.0 * [activity timeIntervalSinceNow];
+}
+
+- (BOOL) isStalled
+{
+ return fStalled;
+}
+
- (NSNumber *) stateSortKey
{
if (![self isActive])