зеркало из https://github.com/mozilla/pjs.git
Fixing bug 318001 - Fatal hang on downloads to the desktop with Quicksilver running, implement kqueue notifications. r=smorgan, sr=mento. Camino head only.
This commit is contained in:
Родитель
206d4adf61
Коммит
567abc1c9e
|
@ -4122,6 +4122,7 @@
|
|||
DE74F74E0AB25EBC00FD1D5B,
|
||||
DEE9EBA50AF5C379002BC511,
|
||||
DEB968190B0D8E0B0023F8B1,
|
||||
DEE34A550B84F5C600BCD687,
|
||||
);
|
||||
isa = PBXHeadersBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -5253,6 +5254,7 @@
|
|||
DE74F7550AB25EDA00FD1D5B,
|
||||
DEE9EBA80AF5C390002BC511,
|
||||
DEB968160B0D8DF70023F8B1,
|
||||
DEE34A580B84F5E100BCD687,
|
||||
);
|
||||
isa = PBXSourcesBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -8013,6 +8015,7 @@
|
|||
DE74F74F0AB25EBC00FD1D5B,
|
||||
DEE9EBA40AF5C379002BC511,
|
||||
DEB968180B0D8E0B0023F8B1,
|
||||
DEE34A540B84F5C600BCD687,
|
||||
);
|
||||
isa = PBXHeadersBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -9145,6 +9148,7 @@
|
|||
DE74F7560AB25EDA00FD1D5B,
|
||||
DEE9EBA70AF5C390002BC511,
|
||||
DEB968150B0D8DF70023F8B1,
|
||||
DEE34A570B84F5E100BCD687,
|
||||
);
|
||||
isa = PBXSourcesBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -14191,6 +14195,50 @@
|
|||
settings = {
|
||||
};
|
||||
};
|
||||
DEE34A530B84F5C600BCD687 = {
|
||||
fileEncoding = 30;
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = FileChangeWatcher.h;
|
||||
path = src/download/FileChangeWatcher.h;
|
||||
refType = 2;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
DEE34A540B84F5C600BCD687 = {
|
||||
fileRef = DEE34A530B84F5C600BCD687;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
DEE34A550B84F5C600BCD687 = {
|
||||
fileRef = DEE34A530B84F5C600BCD687;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
DEE34A560B84F5E100BCD687 = {
|
||||
fileEncoding = 30;
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.objc;
|
||||
name = FileChangeWatcher.m;
|
||||
path = src/download/FileChangeWatcher.m;
|
||||
refType = 2;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
DEE34A570B84F5E100BCD687 = {
|
||||
fileRef = DEE34A560B84F5E100BCD687;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
COMPILER_FLAGS = "-fobjc-exceptions";
|
||||
};
|
||||
};
|
||||
DEE34A580B84F5E100BCD687 = {
|
||||
fileRef = DEE34A560B84F5E100BCD687;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
COMPILER_FLAGS = "-fobjc-exceptions";
|
||||
};
|
||||
};
|
||||
DEE9EBA30AF5C379002BC511 = {
|
||||
fileEncoding = 30;
|
||||
isa = PBXFileReference;
|
||||
|
@ -14975,6 +15023,7 @@
|
|||
F517395B020CE3740189DA0C,
|
||||
3FC0FB7F05A0D2DC002F47DE,
|
||||
3FC0FB8005A0D2DC002F47DE,
|
||||
DEE34A560B84F5E100BCD687,
|
||||
);
|
||||
isa = PBXGroup;
|
||||
name = Camino;
|
||||
|
@ -15340,6 +15389,7 @@
|
|||
F566BD1202EFA9AD01A967F3,
|
||||
F59E9F3D0237E28401A967DF,
|
||||
DE74F74D0AB25EBC00FD1D5B,
|
||||
DEE34A530B84F5C600BCD687,
|
||||
F5137A1102676B9101026D05,
|
||||
F528E218020FD8400168DE43,
|
||||
F5607CB5023944AD01A967DF,
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Nick Kreeger
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Nick Kreeger <nick.kreeger@park.edu>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
//
|
||||
// Any object that needs a file to be polled can implement this protocol and
|
||||
// register itself with the watch queue.
|
||||
//
|
||||
@protocol WatchedFileDelegate
|
||||
|
||||
//
|
||||
// This method will need to return the full path of the file/folder
|
||||
// that is being watched.
|
||||
//
|
||||
-(const char*)representedFilePath;
|
||||
|
||||
//
|
||||
// This method gets called when the watcher recieves news that the
|
||||
// watched path has changed.
|
||||
// Note: This method will be called on a background thread.
|
||||
//
|
||||
-(void)fileDidChange;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// This class provides a file polling service to any object
|
||||
// that implements the |WatchedFileDelegate| protocol.
|
||||
//
|
||||
@interface FileChangeWatcher : NSObject
|
||||
{
|
||||
@private
|
||||
NSMutableArray* mWatchedFileDelegates; // strong ref
|
||||
NSMutableArray* mWatchedFileDescriptors; // strong ref
|
||||
|
||||
int mQueueFileDesc;
|
||||
BOOL mShouldRunThread;
|
||||
BOOL mThreadIsRunning;
|
||||
}
|
||||
|
||||
//
|
||||
// Add an object implementing the |WatchedFileDelegate| to the
|
||||
// watch queue.
|
||||
// Note: An object will only be added once to the queue.
|
||||
//
|
||||
-(void)addWatchedFileDelegate:(id<WatchedFileDelegate>)aWatchedFileDelegate;
|
||||
|
||||
//
|
||||
// Remove an object implementing the |WatchedFileDelegate| from the watch queue.
|
||||
//
|
||||
-(void)removeWatchedFileDelegate:(id<WatchedFileDelegate>)aWatchedFileDelegate;
|
||||
|
||||
@end
|
|
@ -0,0 +1,162 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Nick Kreeger
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Nick Kreeger <nick.kreeger@park.edu>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#import "FileChangeWatcher.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#import "unistd.h"
|
||||
#import "fcntl.h"
|
||||
|
||||
const int kSecondPollingInterval = 60;
|
||||
|
||||
@interface FileChangeWatcher(Private)
|
||||
|
||||
-(void)startPolling;
|
||||
-(void)stopPolling;
|
||||
-(void)pollWatchedDirectories;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FileChangeWatcher
|
||||
|
||||
-(id)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
mWatchedFileDelegates = [[NSMutableArray alloc] init];
|
||||
mWatchedFileDescriptors = [[NSMutableArray alloc] init];
|
||||
mQueueFileDesc = kqueue();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
close(mQueueFileDesc);
|
||||
[mWatchedFileDelegates release];
|
||||
[mWatchedFileDescriptors release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void)addWatchedFileDelegate:(id<WatchedFileDelegate>)aWatchedFileDelegate
|
||||
{
|
||||
if ([mWatchedFileDelegates containsObject:aWatchedFileDelegate])
|
||||
return;
|
||||
|
||||
int fileDesc = open([aWatchedFileDelegate representedFilePath], O_EVTONLY, 0);
|
||||
if (fileDesc >= 0) {
|
||||
struct timespec nullts = { 0, 0 };
|
||||
struct kevent ev;
|
||||
u_int fflags = NOTE_RENAME | NOTE_WRITE | NOTE_DELETE;
|
||||
|
||||
EV_SET(&ev, fileDesc, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, fflags, 0, (void*)aWatchedFileDelegate);
|
||||
|
||||
[mWatchedFileDelegates addObject:aWatchedFileDelegate];
|
||||
[mWatchedFileDescriptors addObject:[NSNumber numberWithInt:fileDesc]];
|
||||
kevent(mQueueFileDesc, &ev, 1, NULL, 0, &nullts);
|
||||
if (!mShouldRunThread && [mWatchedFileDescriptors count] > 0)
|
||||
[self startPolling];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)removeWatchedFileDelegate:(id<WatchedFileDelegate>)aWatchedFileDelegate
|
||||
{
|
||||
int index = [mWatchedFileDelegates indexOfObject:aWatchedFileDelegate];
|
||||
if (index == NSNotFound)
|
||||
return;
|
||||
|
||||
int fileDesc = [[mWatchedFileDescriptors objectAtIndex:index] intValue];
|
||||
[mWatchedFileDelegates removeObjectAtIndex:index];
|
||||
[mWatchedFileDescriptors removeObjectAtIndex:index];
|
||||
close(fileDesc);
|
||||
|
||||
if (mShouldRunThread && [mWatchedFileDelegates count] == 0)
|
||||
[self stopPolling];
|
||||
}
|
||||
|
||||
-(void)startPolling
|
||||
{
|
||||
@synchronized(self) {
|
||||
mShouldRunThread = YES;
|
||||
if (!mThreadIsRunning) {
|
||||
mThreadIsRunning = YES;
|
||||
[NSThread detachNewThreadSelector:@selector(pollWatchedDirectories)
|
||||
toTarget:self
|
||||
withObject:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)stopPolling
|
||||
{
|
||||
@synchronized(self) {
|
||||
mShouldRunThread = NO;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Portions of this method were originally written by M. Uli Kusterer.
|
||||
//
|
||||
-(void)pollWatchedDirectories
|
||||
{
|
||||
const struct timespec timeInterval = { kSecondPollingInterval, 0 };
|
||||
|
||||
while (1) {
|
||||
@synchronized(self) {
|
||||
if (!mShouldRunThread) {
|
||||
mThreadIsRunning = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
NS_DURING
|
||||
struct kevent event;
|
||||
int n = kevent(mQueueFileDesc, NULL, 0, &event, 1, &timeInterval);
|
||||
if (n > 0 && event.filter == EVFILT_VNODE && event.fflags) {
|
||||
[(id<WatchedFileDelegate>)event.udata fileDidChange];
|
||||
}
|
||||
NS_HANDLER
|
||||
NSLog(@"Error in watcherThread: %@", localException);
|
||||
NS_ENDHANDLER
|
||||
|
||||
[pool release];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -23,6 +23,7 @@
|
|||
* Simon Fraser <sfraser@netscape.com>
|
||||
* Calum Robinson <calumr@mac.com>
|
||||
* Josh Aas <josh@mozilla.com>
|
||||
* Nick Kreeger <nick.kreeger@park.edu>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -68,6 +69,7 @@
|
|||
|
||||
#import "CHDownloadProgressDisplay.h"
|
||||
#import "ProgressViewController.h"
|
||||
#import "FileChangeWatcher.h"
|
||||
|
||||
//
|
||||
// interface ProgressDlgController
|
||||
|
@ -79,16 +81,18 @@
|
|||
|
||||
@interface ProgressDlgController : NSWindowController<CHDownloadDisplayFactory, CHStackViewDataSource>
|
||||
{
|
||||
IBOutlet CHStackView *mStackView;
|
||||
IBOutlet NSScrollView *mScrollView;
|
||||
IBOutlet CHStackView* mStackView;
|
||||
IBOutlet NSScrollView* mScrollView;
|
||||
|
||||
NSSize mDefaultWindowSize;
|
||||
NSTimer *mDownloadTimer; // used for updating the status, STRONG ref
|
||||
NSMutableArray *mProgressViewControllers; // the downloads we manage, STRONG ref
|
||||
NSTimer* mDownloadTimer; // used for updating the status, STRONG ref
|
||||
NSMutableArray* mProgressViewControllers; // the downloads we manage, STRONG ref
|
||||
int mNumActiveDownloads;
|
||||
int mSelectionPivotIndex;
|
||||
BOOL mShouldCloseWindow; // true when a download completes when termination modal sheet is up
|
||||
BOOL mAwaitingTermination; // true when we are waiting for users termination modal sheet
|
||||
|
||||
FileChangeWatcher* mFileChangeWatcher; // strong ref.
|
||||
}
|
||||
|
||||
+(ProgressDlgController *)sharedDownloadController; // creates if necessary
|
||||
|
@ -104,7 +108,7 @@
|
|||
|
||||
-(int)numDownloadsInProgress;
|
||||
-(void)clearAllDownloads;
|
||||
-(void)didStartDownload:(id <CHDownloadProgressDisplay>)progressDisplay;
|
||||
-(void)didStartDownload:(ProgressViewController*)progressDisplay;
|
||||
-(void)didEndDownload:(id <CHDownloadProgressDisplay>)progressDisplay withSuccess:(BOOL)completedOK statusCode:(nsresult)status;
|
||||
-(void)removeDownload:(id <CHDownloadProgressDisplay>)progressDisplay suppressRedraw:(BOOL)suppressRedraw;
|
||||
-(NSApplicationTerminateReply)allowTerminate;
|
||||
|
@ -112,4 +116,7 @@
|
|||
-(void)saveProgressViewControllers;
|
||||
-(void)loadProgressViewControllers;
|
||||
|
||||
-(void)addFileDelegateToWatchList:(id<WatchedFileDelegate>)aWatchedFileDelegate;
|
||||
-(void)removeFileDelegateFromWatchList:(id<WatchedFileDelegate>)aWatchedFileDelegate;
|
||||
|
||||
@end
|
||||
|
|
|
@ -142,6 +142,8 @@ static id gSharedProgressController = nil;
|
|||
[toolbar setAutosavesConfiguration:YES];
|
||||
[[self window] setToolbar:toolbar];
|
||||
|
||||
mFileChangeWatcher = [[FileChangeWatcher alloc] init];
|
||||
|
||||
// load the saved instances to mProgressViewControllers array
|
||||
[self loadProgressViewControllers];
|
||||
}
|
||||
|
@ -153,6 +155,7 @@ static id gSharedProgressController = nil;
|
|||
gSharedProgressController = nil;
|
||||
}
|
||||
[mProgressViewControllers release];
|
||||
[mFileChangeWatcher release];
|
||||
[self killDownloadTimer];
|
||||
[super dealloc];
|
||||
}
|
||||
|
@ -526,7 +529,7 @@ static id gSharedProgressController = nil;
|
|||
}
|
||||
}
|
||||
|
||||
-(void)didStartDownload:(id <CHDownloadProgressDisplay>)progressDisplay
|
||||
-(void)didStartDownload:(ProgressViewController*)progressDisplay
|
||||
{
|
||||
if (![[self window] isVisible]) {
|
||||
[self showWindow:nil]; // make sure the window is visible
|
||||
|
@ -645,6 +648,7 @@ static id gSharedProgressController = nil;
|
|||
|
||||
-(void)removeDownload:(id <CHDownloadProgressDisplay>)progressDisplay suppressRedraw:(BOOL)suppressRedraw
|
||||
{
|
||||
[progressDisplay displayWillBeRemoved];
|
||||
[mProgressViewControllers removeObject:progressDisplay];
|
||||
|
||||
if ([mProgressViewControllers count] == 0) {
|
||||
|
@ -808,7 +812,8 @@ static id gSharedProgressController = nil;
|
|||
NSDictionary* downloadsDictionary;
|
||||
while((downloadsDictionary = [downloadsEnum nextObject]))
|
||||
{
|
||||
ProgressViewController* curController = [[ProgressViewController alloc] initWithDictionary:downloadsDictionary];
|
||||
ProgressViewController* curController = [[ProgressViewController alloc] initWithDictionary:downloadsDictionary
|
||||
andWindowController:self];
|
||||
[mProgressViewControllers addObject:curController];
|
||||
[curController release];
|
||||
}
|
||||
|
@ -817,6 +822,16 @@ static id gSharedProgressController = nil;
|
|||
}
|
||||
}
|
||||
|
||||
-(void)addFileDelegateToWatchList:(id<WatchedFileDelegate>)aWatchedFileDelegate
|
||||
{
|
||||
[mFileChangeWatcher addWatchedFileDelegate:aWatchedFileDelegate];
|
||||
}
|
||||
|
||||
-(void)removeFileDelegateFromWatchList:(id<WatchedFileDelegate>)aWatchedFileDelegate
|
||||
{
|
||||
[mFileChangeWatcher removeWatchedFileDelegate:aWatchedFileDelegate];
|
||||
}
|
||||
|
||||
// Remove the successful downloads from the downloads list
|
||||
-(void)removeSuccessfulDownloads
|
||||
{
|
||||
|
@ -1201,8 +1216,7 @@ static id gSharedProgressController = nil;
|
|||
*/
|
||||
-(id <CHDownloadProgressDisplay>)createProgressDisplay
|
||||
{
|
||||
ProgressViewController *newController = [[[ProgressViewController alloc] init] autorelease];
|
||||
[newController setProgressWindowController:self];
|
||||
ProgressViewController* newController = [[[ProgressViewController alloc] initWithWindowController:self] autorelease];
|
||||
[mProgressViewControllers addObject:newController];
|
||||
|
||||
return newController;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
|
||||
#import "CHDownloadProgressDisplay.h"
|
||||
#import "FileChangeWatcher.h"
|
||||
|
||||
class CHDownloader;
|
||||
@class ProgressDlgController;
|
||||
|
@ -70,7 +71,7 @@ const int kRemoveUponSuccessfulDownloadPrefValue = 2;
|
|||
// well as managing the download. It holds onto two views, one for while
|
||||
// the item is downloading, the other for after it has completed.
|
||||
//
|
||||
@interface ProgressViewController : NSObject<CHDownloadProgressDisplay>
|
||||
@interface ProgressViewController : NSObject<CHDownloadProgressDisplay, WatchedFileDelegate>
|
||||
{
|
||||
IBOutlet NSProgressIndicator *mProgressBar;
|
||||
|
||||
|
@ -83,10 +84,8 @@ const int kRemoveUponSuccessfulDownloadPrefValue = 2;
|
|||
BOOL mDownloadDone;
|
||||
BOOL mRefreshIcon;
|
||||
BOOL mFileExists;
|
||||
BOOL mFileIsWatched;
|
||||
BOOL mIsSelected;
|
||||
|
||||
FNSubscriptionRef mSubRef;
|
||||
FNSubscriptionUPP mSubUPP;
|
||||
|
||||
NSTimeInterval mDownloadTime; // only set when done
|
||||
|
||||
|
@ -106,7 +105,10 @@ const int kRemoveUponSuccessfulDownloadPrefValue = 2;
|
|||
+(NSString *)formatFuzzyTime:(int)aSeconds;
|
||||
+(NSString *)formatBytes:(float)aBytes;
|
||||
|
||||
-(id)initWithDictionary:(NSDictionary*)aDict;
|
||||
-(id)initWithWindowController:(ProgressDlgController*)aWindowController;
|
||||
-(id)initWithDictionary:(NSDictionary*)aDict
|
||||
andWindowController:(ProgressDlgController*)aWindowController;
|
||||
|
||||
-(ProgressView *)view;
|
||||
|
||||
-(IBAction)cancel:(id)sender;
|
||||
|
@ -132,6 +134,4 @@ const int kRemoveUponSuccessfulDownloadPrefValue = 2;
|
|||
|
||||
-(NSMenu*)contextualMenu;
|
||||
|
||||
-(void)setProgressWindowController:(ProgressDlgController*)progressWindowController;
|
||||
|
||||
@end
|
||||
|
|
|
@ -59,13 +59,6 @@ enum {
|
|||
kLabelTagIcon
|
||||
};
|
||||
|
||||
// Method helps set up a subscription to the download dir to listen for changes
|
||||
static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void* refcon, FNSubscriptionRef subscription)
|
||||
{
|
||||
[(ProgressViewController*)refcon checkFileExists];
|
||||
}
|
||||
|
||||
|
||||
@interface ProgressViewController(ProgressViewControllerPrivate)
|
||||
|
||||
-(void)viewDidLoad;
|
||||
|
@ -166,10 +159,20 @@ static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void
|
|||
return self;
|
||||
}
|
||||
|
||||
-(id)initWithDictionary:(NSDictionary*)aDict
|
||||
-(id)initWithWindowController:(ProgressDlgController*)aWindowController
|
||||
{
|
||||
if ((self = [self init]))
|
||||
mProgressWindowController = aWindowController;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(id)initWithDictionary:(NSDictionary*)aDict
|
||||
andWindowController:(ProgressDlgController*)aWindowController
|
||||
{
|
||||
if ((self = [self init]))
|
||||
{
|
||||
mProgressWindowController = aWindowController;
|
||||
[self setProgressViewFromDictionary:aDict];
|
||||
}
|
||||
|
||||
|
@ -197,8 +200,6 @@ static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void
|
|||
[mCompletedView setController:nil];
|
||||
[mProgressView setController:nil];
|
||||
|
||||
[self unsubscribeFileSystemNotification];
|
||||
|
||||
[mStartTime release];
|
||||
[mSourceURL release];
|
||||
[mDestPath release];
|
||||
|
@ -250,35 +251,20 @@ static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void
|
|||
|
||||
-(void)setupFileSystemNotification
|
||||
{
|
||||
// there is some update, that is why we are being called again
|
||||
// unsubscribe the old stuff and create a fresh subscription
|
||||
[self unsubscribeFileSystemNotification];
|
||||
|
||||
[self checkFileExists];
|
||||
|
||||
NSString *dir = [mDestPath stringByDeletingLastPathComponent];
|
||||
if (dir)
|
||||
{
|
||||
mSubUPP = NewFNSubscriptionUPP(FileSystemNotificationProc);
|
||||
OSStatus err = FNSubscribeByPath(((const UInt8*)[dir fileSystemRepresentation]), mSubUPP, (void*)self, nil, &mSubRef);
|
||||
if (err != noErr)
|
||||
NSLog(@"Failed to subscribe to file system notification for %@", dir);
|
||||
if (mFileExists && !mFileIsWatched) {
|
||||
// Adding ourselves to the watch kqueue creates an extra ref-count to our instance.
|
||||
// We will remove ourselves from the watch kqueue on |displayWillBeRemoved|, which
|
||||
// will remove the extra ref count from our instance.
|
||||
[mProgressWindowController addFileDelegateToWatchList:self];
|
||||
mFileIsWatched = YES;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)unsubscribeFileSystemNotification
|
||||
{
|
||||
if (mSubRef)
|
||||
{
|
||||
FNUnsubscribe(mSubRef);
|
||||
mSubRef = nil;
|
||||
}
|
||||
|
||||
if (mSubUPP)
|
||||
{
|
||||
DisposeFNSubscriptionUPP(mSubUPP);
|
||||
mSubUPP = nil;
|
||||
}
|
||||
[mProgressWindowController removeFileDelegateFromWatchList:self];
|
||||
mFileIsWatched = NO;
|
||||
}
|
||||
|
||||
-(IBAction)copySourceURL:(id)sender
|
||||
|
@ -505,11 +491,6 @@ static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void
|
|||
}
|
||||
}
|
||||
|
||||
-(void)setProgressWindowController:(ProgressDlgController*)progressWindowController
|
||||
{
|
||||
mProgressWindowController = progressWindowController;
|
||||
}
|
||||
|
||||
-(BOOL)isActive
|
||||
{
|
||||
return !mDownloadDone;
|
||||
|
@ -602,6 +583,21 @@ static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void
|
|||
return dict;
|
||||
}
|
||||
|
||||
-(const char*)representedFilePath
|
||||
{
|
||||
return [mDestPath fileSystemRepresentation];
|
||||
}
|
||||
|
||||
-(void)fileDidChange
|
||||
{
|
||||
// This method gets called on a background thread, so switch the |checkFileExists| call to the main thread.
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
[self performSelectorOnMainThread:@selector(checkFileExists)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
[pool release];
|
||||
}
|
||||
|
||||
-(NSMenu*)contextualMenu
|
||||
{
|
||||
NSMenu *menu = [[NSMenu alloc] init];
|
||||
|
@ -691,6 +687,8 @@ static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void
|
|||
|
||||
[self downloadDidEnd];
|
||||
[mProgressWindowController didEndDownload:self withSuccess:completedOK statusCode:aStatus];
|
||||
if (completedOK)
|
||||
[self setupFileSystemNotification];
|
||||
}
|
||||
|
||||
-(void)setProgressTo:(long long)aCurProgress ofMax:(long long)aMaxProgress
|
||||
|
@ -775,13 +773,26 @@ static void FileSystemNotificationProc(FNMessage message, OptionBits flags, void
|
|||
{
|
||||
[mDestPath autorelease];
|
||||
mDestPath = [aDestPath copy];
|
||||
[self setupFileSystemNotification];
|
||||
if (mDownloadDone)
|
||||
[self setupFileSystemNotification];
|
||||
//[self tryToSetFinderComments];
|
||||
}
|
||||
|
||||
- (NSString*)destinationPath
|
||||
-(NSString*)destinationPath
|
||||
{
|
||||
return mDestPath;
|
||||
}
|
||||
|
||||
//
|
||||
// This method exists because of an extra ref-count to ourselves in
|
||||
// |FileChangeWatcher|. To remove this extra refcount before |dealloc|,
|
||||
// this class gets notified when the view is about to be removed.
|
||||
//
|
||||
-(void)displayWillBeRemoved
|
||||
{
|
||||
// The file can only be watched if the download compeleted sucessfully
|
||||
if (mFileIsWatched)
|
||||
[self unsubscribeFileSystemNotification];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -121,6 +121,8 @@ class CHDownloader;
|
|||
- (void)setDestinationPath:(NSString*)aDestPath;
|
||||
- (NSString*)destinationPath;
|
||||
|
||||
- (void)displayWillBeRemoved;
|
||||
|
||||
@end
|
||||
|
||||
// A formal protocol which is implemented by a factory of progress UI.
|
||||
|
|
Загрузка…
Ссылка в новой задаче